it-swarm.com.de

Unit Testing Bash-Skripte

Wir haben ein System, auf dem neben Java-Code einige Bash-Skripts ausgeführt werden. Da wir versuchen, alles zu testen, was möglicherweise brechen könnte, und diese Bash-Skripts möglicherweise brechen, möchten wir sie testen. 

Das Problem ist, dass es schwierig ist, Bash-Skripte zu testen.

Gibt es eine Möglichkeit oder eine bewährte Methode, um Bash-Skripte zu testen? Oder sollten wir mit der Verwendung von Bash-Skripts aufhören und nach alternativen Lösungen suchen, die überprüfbar sind?

89
nimcap

Ich habe folgende Antwort von einer Diskussionsgruppe erhalten:

es ist möglich, eine Prozedur (Funktion, .__, wie auch immer sie benannt wird) von einer externen Datei. Das ist der Schlüssel zum Schreiben eines Test-Skript: Sie trennen Ihr Skript in unabhängige Prozeduren das kann dann in beide importiert werden Ihr laufendes Skript und Ihre Tests Skript, und dann haben Sie Ihre Skript so einfach wie möglich sein.

Diese Methode ähnelt der Abhängigkeitseingabe für Skripte und klingt vernünftig. Das Vermeiden von Bash-Skripten und die Verwendung einer überprüfbaren und weniger obskuren Sprache ist zu bevorzugen.

26
nimcap

Für Shell-Skripte gibt es tatsächlich ein Unit-Test-Framework . Ich habe es selbst nicht benutzt, aber es lohnt sich vielleicht.

Ähnliche Fragen wurden bereits gestellt: 

40
ire_and_curses

TAP - konforme Bash-Tests: Automatisches Bash-Testsystem

TAP, das Test Anything Protocol, ist eine einfache textbasierte Schnittstelle zwischen Testmodulen in einem Testkabelbaum. TAP wurde als Teil der Testumgebung für Perl ins Leben gerufen, hat jedoch Implementierungen in C, C++, Python, PHP, Perl, Java, JavaScript und anderen.

Fledermauskern

20
Janus Troelsen

Epoxy ist ein Bash-Testframework, das ich hauptsächlich für das Testen anderer Software entwickelt habe, aber ich verwende es auch zum Testen von Bash-Modulen, einschließlich selbst und Carton .

Hauptvorteile sind ein relativ geringer Codieraufwand, eine unbegrenzte Assertionsverschachtelung und eine flexible Auswahl der zu überprüfenden Assertions.

Ich habe eine Präsentation gemacht sie mit BeakerLib verglichen - ein Framework, das einige von Red Hat verwenden.

7
spbnick

Warum sagen Sie, dass es "schwer" ist, Bash-Skripte zu testen?

Was ist falsch an Test-Wrappern:

 #!/bin/bash
 set -e
 errors=0
 results=$($script_under_test $args<<ENDTSTDATA
 # inputs
 # go
 # here
 #
 ENDTSTDATA
 )
 [ "$?" -ne 0 ] || {
     echo "Test returned error code $?" 2>&1
     let errors+=1
     }

 echo "$results" | grep -q $expected1 || {
      echo "Test Failed.  Expected $expected1"
      let errors+=1
 }
 # and so on, et cetera, ad infinitum, ad nauseum
 [ "$errors" -gt 0 ] && {
      echo "There were $errors errors found"
      exit 1
 }
6
Jim Dennis

Ich kann nicht glauben, dass niemand darüber gesprochen hat OSHT ! Es ist kompatibel mit sowohl TAP als auch JUnit, es ist reine Shell (das heißt, es sind keine anderen Sprachen involviert), es funktioniert auch eigenständig und es ist einfach und direkt.

Das Testen sieht folgendermaßen aus (Ausschnitte aus der Projektseite):

#!/bin/bash
. osht.sh

# Optionally, indicate number of tests to safeguard against abnormal exits
PLAN 13

# Comparing stuff
IS $(whoami) != root
var="foobar"
IS "$var" =~ foo
ISNT "$var" == foo

# test(1)-based tests
OK -f /etc/passwd
NOK -w /etc/passwd

# Running stuff
# Check exit code
RUNS true
NRUNS false

# Check stdio/stdout/stderr
RUNS echo -e 'foo\nbar\nbaz'
GREP bar
OGREP bar
NEGREP . # verify empty

# diff output
DIFF <<EOF
foo
bar
baz
EOF

# TODO and SKIP
TODO RUNS false
SKIP test $(uname -s) == Darwin

Ein einfacher Lauf:

$ bash test.sh
1..13
ok 1 - IS $(whoami) != root
ok 2 - IS "$var" =~ foo
ok 3 - ISNT "$var" == foo
ok 4 - OK -f /etc/passwd
ok 5 - NOK -w /etc/passwd
ok 6 - RUNS true
ok 7 - NRUNS false
ok 8 - RUNS echo -e 'foo\nbar\nbaz'
ok 9 - GREP bar
ok 10 - OGREP bar
ok 11 - NEGREP . # verify empty
ok 12 - DIFF <<EOF
not ok 13 - TODO RUNS false # TODO Test Know to fail

Der letzte Test wird als "nicht in Ordnung" angezeigt, aber der Beendigungscode ist 0, da es sich um ein TODO handelt. Man kann auch verbose setzen:

$ OSHT_VERBOSE=1 bash test.sh # Or -v
1..13
# dcsobral \!= root
ok 1 - IS $(whoami) != root
# foobar =\~ foo
ok 2 - IS "$var" =~ foo
# \! foobar == foo
ok 3 - ISNT "$var" == foo
# test -f /etc/passwd
ok 4 - OK -f /etc/passwd
# test \! -w /etc/passwd
ok 5 - NOK -w /etc/passwd
# RUNNING: true
# STATUS: 0
# STDIO <<EOM
# EOM
ok 6 - RUNS true
# RUNNING: false
# STATUS: 1
# STDIO <<EOM
# EOM
ok 7 - NRUNS false
# RUNNING: echo -e foo\\nbar\\nbaz
# STATUS: 0
# STDIO <<EOM
# foo
# bar
# baz
# EOM
ok 8 - RUNS echo -e 'foo\nbar\nbaz'
# grep -q bar
ok 9 - GREP bar
# grep -q bar
ok 10 - OGREP bar
# \! grep -q .
ok 11 - NEGREP . # verify empty
ok 12 - DIFF <<EOF
# RUNNING: false
# STATUS: 1
# STDIO <<EOM
# EOM
not ok 13 - TODO RUNS false # TODO Test Know to fail

Benennen Sie es um, um eine .t -Erweiterung zu verwenden, und speichern Sie es in einem t -Unterverzeichnis. Verwenden Sie prove(1) (Teil von Perl), um es auszuführen:

$ prove
t/test.t .. ok
All tests successful.
Files=1, Tests=13,  0 wallclock secs ( 0.03 usr  0.01 sys +  0.11 cusr  0.16 csys =  0.31 CPU)
Result: PASS

Stellen Sie OSHT_JUNIT ein oder übergeben Sie -j, um eine JUnit-Ausgabe zu erzeugen. JUnit kann auch mit prove(1) kombiniert werden.

Ich habe diese Bibliothek sowohl zum Testen von Funktionen als auch zum Ausführen von Zusicherungen mit IS/OK und deren Negativen sowie von Skripten mit RUN/NRUN verwendet. Für mich bietet dieses Framework den größten Gewinn bei geringstem Overhead.

3

Versuchen Sie es mit assert.sh

source "./assert.sh"

local expected actual
expected="Hello"
actual="World!"
assert_eq "$expected" "$actual" "not equivalent!"
# => x Hello == World :: not equivalent!

Ich hoffe es hilft!

3
Mark

Nikita Sobolev hat einen hervorragenden Blogbeitrag geschrieben, in dem ein paar verschiedene Bash-Test-Frameworks verglichen werden: Testing Bash-Anwendungen

Für Ungeduldige: Nikitas Schlussfolgerung war die Verwendung von Bats , aber es scheint, dass Nikita das Bats-Core -Projekt verpasst hat, was mir scheint, dass es zukünftig das zu verwenden scheint, da das ursprüngliche Bats-Projekt nicht aktiv war seit 2013 gepflegt.

3
cb2

Versuchen Sie bashtest . Es ist ein einfacher Weg, Ihre Skripte zu testen. Beispielsweise haben Sie do-some-work.sh, die einige Konfigurationsdateien ändern. Fügen Sie der Konfigurationsdatei PASSWORD = 'XXXXX' beispielsweise eine neue Zeile /etc/my.cfg hinzu.

Sie schreiben zeilenweise bash-Befehle und prüfen dann die Ausgabe.

Installieren:

pip3 install bashtest

Tests erstellen ist ein einfaches Schreiben von Bash-Befehlen. 

Datei test-do-some-work.bashtest:

# run the script  
$ ./do-some-work.sh > /dev/null

# testing that the line "PASSWORD = 'XXXXX'" is in the file /etc/my.cfg   
$ grep -Fxq "PASSWORD = 'XXXXX'" /etc/my.cfg && echo "YES"
YES

Tests ausführen: 

bashtest *.bashtest

einige Beispiele finden Sie hier und hier

3
pahaz

Ich mag Shell2junit , ein Dienstprogramm zum Generieren von JUnit-ähnlichen Ausgaben aus Bash-Skripttests. Dies ist nützlich, da der erstellte Bericht dann von kontinuierlichen Integrationssystemen gelesen werden kann, beispielsweise von den JUnit-Plug-Ins für Jenkins und Bamboo.

Obwohl Shell2junit nicht das umfassende Bash-Skript-Framework wie shunit2 bietet, können Sie die Testergebnisse in Nice anzeigen.

3
Steve HHH

Vielleicht kann dies verwendet werden oder dazu beigetragen werden

https://thorsteinssonh.github.io/bash_test_tools/

Es ist beabsichtigt, Ergebnisse im TAP-Protokoll zu schreiben, von denen ich annehme, dass sie gut für CI sind, und für diejenigen, die Shell-Umgebungen wollen. Ich stelle mir vor, dass einige Dinge in Shell-Umgebungen laufen, daher könnten einige argumentieren, dass sie in ihrer Shell-Umgebung getestet werden sollten.

3
hrob

Ich habe shellspec erstellt, weil ich ein benutzerfreundliches und nützliches Tool haben wollte.

Es wurde mit reinem POSIX-Shell-Skript geschrieben. Es hat mit vielen Shells mehr als shunit2 getestet. Es hat leistungsfähige Funktionen als Fledermäuse/Fledermaus-Kern.

Zum Beispiel Unterstützung verschachtelter Blöcke, einfach zu verspotten, einfach zu überspringen, parametrisierte Tests, Assertion-Zeilennummer, Ausführung nach Zeilennummer, parallele Ausführung, zufällige Ausführung, TAP/JUnit-Formatierer, Coverage und CI-Integration, Profiler usw .

Sehen Sie sich die Demo auf der Projektseite an.

2

Ich habe viele der hier vorgestellten Lösungen ausprobiert, fand die meisten jedoch sperrig und schwierig zu verwenden. Deshalb habe ich mein eigenes kleines Testframework erstellt: https://github.com/meonlol/t-bash

Es ist nur eine Datei im Repo, die Sie einfach direkt ausführen können, mit einer Reihe grundlegender Aussagen im JUnit-Stil.

Ich habe es professionell in mehreren internen Projekten verwendet und konnte unsere Bash-Skripte super stabil und regressionsresistent machen.

1
leondepeon

Vielleicht möchten Sie einen Blick auf bash_unit werfen:

https://github.com/pgrange/bash_unit

0
pgrange

Werfen Sie einen Blick auf Outthentic , es ist einfach und kann durch viele Sprachen (Perl, Python, Ruby, Bash nach Wahl) und ein plattformübergreifendes Framework (Linux, Windows) erweitert werden, um Befehlszeilenanwendungen zu testen.

0
Alexey Melezhik