Nahezu jedes Produkt, an dem ich im Laufe der Jahre gearbeitet habe, enthielt einige Shell-Skripte (oder Batch-Dateien, PowerShell usw. unter Windows). Obwohl wir den Großteil des Codes in Java oder C ++ geschrieben haben, schien es immer einige Integrations- oder Installationsaufgaben zu geben, die besser mit einem Shell-Skript erledigt werden konnten.
Die Shell-Skripte werden somit Teil des ausgelieferten Codes und müssen daher genau wie der kompilierte Code getestet werden. Hat jemand Erfahrung mit einigen der verfügbaren Shell-Skript-Unit-Test-Frameworks, wie z. B. shunit2 ? Ich interessiere mich momentan hauptsächlich für Linux-Shell-Skripte. Ich möchte wissen, wie gut das Testkabel die Funktionalität und Benutzerfreundlichkeit anderer xUnit-Frameworks dupliziert und wie einfach es ist, es in Continuous-Build-Systeme wie CruiseControl oder Hudson zu integrieren.
quelle
Antworten:
UPDATE 2019-03-01: Ich bevorzuge jetzt Fledermäuse . Ich habe es für ein paar Jahre bei kleinen Projekten verwendet. Ich mag die saubere, prägnante Syntax. Ich habe es nicht in CI / CD-Frameworks integriert, aber sein Exit-Status spiegelt den Gesamterfolg / Misserfolg der Suite wider, der besser ist als shunit2, wie unten beschrieben.
VORHERIGE ANTWORT:
Ich verwende shunit2 für Shell-Skripte, die sich auf eine Java / Ruby-Webanwendung in einer Linux-Umgebung beziehen. Es war einfach zu bedienen und keine große Abweichung von anderen xUnit-Frameworks.
Ich habe nicht versucht, mich in CruiseControl oder Hudson / Jenkins zu integrieren, aber bei der Implementierung einer kontinuierlichen Integration auf andere Weise bin ich auf folgende Probleme gestoßen:
quelle
Ich frage mich, warum niemand BATS erwähnt hat . Es ist aktuell und TAP- konform.
Beschreiben:
#!/usr/bin/env bats @test "addition using bc" { result="$(echo 2+2 | bc)" [ "$result" -eq 4 ] }
Lauf:
quelle
Roundup von @ blake-mizerany klingt großartig, und ich sollte es in Zukunft nutzen, aber hier ist mein "Poor-Man" -Ansatz für die Erstellung von Unit-Tests:
functions.sh
undsource
in das Skript. Sie könnensource `dirname $0`/functions.sh
für diesen Zweck verwenden.functions.sh
Betten Sie Ihre Testfälle am Ende von in die folgende Bedingung ein:if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then fi
Ihre Tests sind wörtliche Aufrufe der Funktionen, gefolgt von einfachen Überprüfungen auf Exit-Codes und Variablenwerte. Ich möchte eine einfache Dienstprogrammfunktion wie die folgende hinzufügen, um das Schreiben zu vereinfachen:
function assertEquals() { msg=$1; shift expected=$1; shift actual=$1; shift if [ "$expected" != "$actual" ]; then echo "$msg EXPECTED=$expected ACTUAL=$actual" exit 2 fi }
Führen Sie schließlich
functions.sh
direkt aus, um die Tests auszuführen.Hier ist ein Beispiel, um den Ansatz zu zeigen:
#!/bin/bash function adder() { return $(($1+$2)) } ( [[ "${BASH_SOURCE[0]}" == "${0}" ]] || exit 0 function assertEquals() { msg=$1; shift expected=$1; shift actual=$1; shift /bin/echo -n "$msg: " if [ "$expected" != "$actual" ]; then echo "FAILED: EXPECTED=$expected ACTUAL=$actual" else echo PASSED fi } adder 2 3 assertEquals "adding two numbers" 5 $? )
quelle
exit 0
"Quelle" (diejenige, die dies bezieht) beendet? Ich denke du suchstreturn
hier.exit 0
beendet nur die Subshell.Neben Roundup und shunit2 meine Übersicht über Shell - Einheit Test - Tools ebenfalls enthalten assert.sh und shelltestrunner .
Ich stimme größtenteils der Kritik des Roundup-Autors an shunit2 zu (einige davon subjektiv), daher habe ich shunit2 ausgeschlossen, nachdem ich mir die Dokumentation und Beispiele angesehen habe. Obwohl es mir bekannt vorkam, einige Erfahrungen mit jUnit zu haben.
Meiner Meinung nach ist shelltestrunner das originellste der Tools, die ich mir angesehen habe, da es eine einfache deklarative Syntax für die Definition von Testfällen verwendet. Wie üblich bietet jede Abstraktionsebene eine gewisse Bequemlichkeit auf Kosten einer gewissen Flexibilität. Obwohl die Einfachheit attraktiv ist, fand ich das Tool für den Fall, den ich hatte, zu einschränkend, hauptsächlich weil es keine Möglichkeit gab, Setup- / TearDown-Aktionen zu definieren (z. B. Eingabedateien vor einem Test bearbeiten, Statusdateien nach einem Test entfernen , etc.).
Ich war zunächst ein wenig verwirrt, dass assert.sh nur das Aktivieren des Ausgabe- oder Exit-Status erlaubt, während ich beides brauchte. Lange genug, um ein paar Testfälle mit Roundup zu schreiben. Ich fand den
set -e
Modus der Zusammenfassung jedoch bald unpraktisch, da in einigen Fällen ein Exit-Status ungleich Null erwartet wird, um das Ergebnis zusätzlich zu stdout zu kommunizieren, wodurch der Testfall in diesem Modus fehlschlägt. Eine der Proben zeigt die Lösung:status=$(set +e ; rup roundup-5 >/dev/null ; echo $?)
Aber was ist, wenn ich sowohl den Exit-Status ungleich Null als auch den Ausgang benötige? Ich könnte natürlich
set +e
vor dem Aufruf undset -e
nach oderset +e
für den gesamten Testfall. Aber das widerspricht dem Prinzip der Zusammenfassung "Alles ist eine Behauptung" . Es fühlte sich also so an, als würde ich anfangen, gegen das Werkzeug zu arbeiten.Bis dahin habe ich erkannt, dass der "Nachteil" von assert.sh, nur den Exit-Status oder die Ausgabe zu bestätigen, eigentlich kein Problem ist, da ich nur
test
mit einem zusammengesetzten Ausdruck wie diesem übergeben kannoutput=$($tested_script_with_args) status=$? expected_output="the expectation" assert_raises "test \"$output\" = \"$expected_output\" -a $status -eq 2"
Da meine Anforderungen wirklich grundlegend waren (eine Reihe von Tests durchführen, anzeigen, dass alles in Ordnung war oder was fehlgeschlagen ist), mochte ich die Einfachheit von assert.sh, also habe ich mich für diese entschieden.
quelle
Ich habe kürzlich ein neues Test-Framework namens Shellspec veröffentlicht.
Shellspec ist ein Testframework im BDD-Stil. Es funktioniert mit POSIX-kompatiblen Shell-Skripten wie Bash, Dash, Ksh, Busybox usw.
Natürlich spiegelt der Exit-Status das Ergebnis der Ausführung der Spezifikationen wider und verfügt über einen TAP-kompatiblen Formatierer.
Die Spezifikationsdatei kommt der natürlichen Sprache nahe und ist leicht zu lesen. Außerdem ist sie mit Shell-Skripten kompatibel.
#shellcheck shell=sh Describe 'sample' Describe 'calc()' calc() { echo "$(($*))"; } It 'calculates the formula' When call calc 1 + 2 The output should equal 3 End End End
quelle
Sie sollten die assert.sh lib ausprobieren , sehr praktisch, einfach zu bedienen
local expected actual expected="Hello" actual="World!" assert_eq "$expected" "$actual" "not equivalent!" # => x Hello == World :: not equivalent!
quelle