2009-06-09 12 views
58

Fast jedes Produkt, an dem ich im Laufe der Jahre gearbeitet habe, beinhaltete ein gewisses Maß an Shell-Skripten (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 wurden.Komponententests für Shell-Skripte

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 Shell-Skripteinheit Frameworks, die da draußen sind, wie shunit2? Ich interessiere mich hauptsächlich für Linux-Shell-Skripte; Ich würde gerne wissen, wie gut die Testumgebung die Funktionalität und Benutzerfreundlichkeit anderer xUnit-Frameworks verdoppelt und wie einfach es ist, sie in Systeme mit kontinuierlichem Build wie CruiseControl oder Hudson zu integrieren.

+1

Sie können auch bashtest util überprüfen: https: // GitHub.com/pahaz/bashtest (es ist eine einfache Möglichkeit, bash-Tests zu schreiben) – pahaz

+0

Roundup formalisiert einige Aufgaben/Tags für Sie. Sobald Sie über den Lernhöcker kommen, ist es sehr nützlich. Persönlich mag ich die Vorgehensweise von haridsv besser, da ich nicht ein anderes Paket installieren muss. Ich habe diesen Ansatz auf Shell-Skript und Python-Tests angewendet. – todo

+1

Checkout diese Übersicht über fast jedes mögliche Werkzeug: https://medium.com/wemake-services/testing-bash-applications-85512e7fe2de – sobolevn

Antwort

42

Ich benutze shunit2 für Shell-Skripte im Zusammenhang mit einer Java/Ruby-Web-Anwendung in einer Linux-Umgebung. Es war einfach zu verwenden und keine große Abweichung von anderen xUnit-Frameworks.

ich versucht habe, nicht mit CruiseControl- oder Hudson/Jenkins zu integrieren, aber die kontinuierliche Integration über andere Mittel bei der Umsetzung habe ich diese Probleme gestoßen:

  • Endestatus: Wenn eine Testsuite ausfällt, shunit2 nicht verwenden ist ein Nicht-Null-Exit-Status, um den Fehler zu kommunizieren. Sie müssen also entweder die Ausgabe von shunit2 analysieren, um das Bestehen/Nichtbestehen einer Suite zu bestimmen, oder shunit2 so ändern, dass sie sich so verhalten, wie es einige Continuous Integration Frameworks erwarten, und Pass/Fail über Exit-Status kommunizieren.
  • XML-Protokolle: shunit2 erzeugt kein JUnit-ähnliches XML-Protokoll der Ergebnisse.
+0

Pete, ich bin sehr nah an der Veröffentlichung einer Unit-Test-Bibliothek, die für bash und ksh funktioniert, sehr einfach zu bedienen. Können Sie mir irgendwo einen Link zum XML-Protokoll im Junit-Stil schicken, damit ich sehen kann, was darin enthalten ist? Möchten Sie auch den Exit-Status für einen einzelnen fehlgeschlagenen Test oder am Ende, wenn er abgeschlossen ist, wenn> 0 Test fehlschlagen, Exit 1? Die Art, wie ich es jetzt mache, ist, dass es eine Funktion gibt, die man aufrufen kann, um die Anzahl der bestandenen/fehlgeschlagenen Tests zu erhalten. –

+0

@EthanPost Ich verwende/benötige keine XML-Protokolle mehr. Sie finden vielleicht Hilfe, indem Sie nach Dingen wie "xunit xml format" suchen. Dinge wie diese: https://xunit.github.io/docs/format-xml-v2.html –

16

Roundup: http://bmizerany.github.com/roundup/

Es gibt einen Link zu einem Artikel in der Readme es im Detail zu erklären.

+1

Roundup empfiehlt auch [contest] (https://github.com/citrusbyte/contest) –

20

Roundup von @ blake-mizerany klingen großartig, und ich soll Gebrauch davon in der Zukunft machen, aber hier ist mein „armer Mann“ Ansatz Unit-Tests für die Erstellung von:

  • Separate alles prüfbar als Funktion.
  • Verschieben Sie Funktionen in eine externe Datei, sagen functions.sh und source es in das Skript. Sie können source `dirname $0`/functions.sh für diesen Zweck verwenden.
  • Am Ende functions.sh, betten Sie Ihre Testfälle in der unten, wenn Bedingung:

    if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then 
    fi 
    
  • Ihre Tests wörtliche Anrufe auf die Funktionen, gefolgt von einfachen Prüfungen für Exit-Codes und Variablenwerte sind. Ich mag eine einfache Nutzenfunktion wie unten hinzufügen, um es zu schreiben, macht einfach:

    function assertEquals() 
    { 
        msg=$1; shift 
        expected=$1; shift 
        actual=$1; shift 
        if [ "$expected" != "$actual" ]; then 
         echo "$msg EXPECTED=$expected ACTUAL=$actual" 
         exit 2 
        fi 
    } 
    
  • Schließlich functions.sh direkt ausführen, um die Tests auszuführen.

Hier ist eine Probe, die 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 $? 
    ) 
+1

Schön, danke - ich wirklich wie die strukturierte Programmierung von Shell-Skripten. –

+0

Sehr gute Beobachtung dort: 'Alles testbar als Funktion trennen'. Es ist wichtig, auch wenn Sie (noch) keinen Test dafür schreiben. Dies ist ein wesentlicher Faktor zur Verbesserung der Lesbarkeit von Codes. Vor ein paar Jahren begann ich mein (ksh) Skript nach diesem Prinzip zu schreiben. Schreibe alles als eine Funktion. –

+0

@HenkLangeveld Wird die 'exit 0' nicht dazu führen, dass die" sourcee "(diejenige, die diese Quelle abgibt) ebenfalls austritt? Ich denke, du suchst hier "Rückkehr". – haridsv

6

Neben roundup und shunit2 meine Übersicht über auch Test-Tools Shell-Einheit enthalten assert.sh und shelltestrunner.

Ich stimme größtenteils mit der Kritik des Verfassers von shunit2 (einige davon subjektiv) überein, so dass ich shunit2 ausschloss, nachdem ich die Dokumentation und die Beispiele angeschaut hatte. Obwohl es vertraut war, einige Erfahrungen mit jUnit gemacht zu haben.

Meiner Meinung nach ist Shellstrunner das originellste der Tools, die ich untersucht habe, da es eine einfache deklarative Syntax für die Testfalldefinition verwendet. Wie üblich bietet jede Ebene der Abstraktion eine gewisse Bequemlichkeit auf Kosten einer gewissen Flexibilität. Obwohl die Einfachheit attraktiv ist, fand ich das Tool zu einschränkend für den Fall, den ich hatte, 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 erlaubt, entweder Ausgang oder Ausgang Status geltend zu machen, während ich beide brauchte. Lange genug, um ein paar Testfälle mit Roundup zu schreiben. Aber ich fand bald den set -e Modus des Ansatzes unbequem, da in einigen Fällen ein Nicht-Null-Exit-Status als Mittel zum Kommunizieren des Ergebnisses zusätzlich zu stdout erwartet wird, was den Testfall in diesem Modus versagt. One of the samples zeigt die Lösung:

status=$(set +e ; rup roundup-5 >/dev/null ; echo $?) 

Aber was, wenn ich sowohl den Nicht-Null-Exit-Status und die Ausgabe benötigen? Ich könnte natürlich set +e vor dem Aufruf und set -e nach oder set +e für den gesamten Testfall. Aber das ist gegen das Prinzip der Zusammenfassung "Everything is an Assertion". Es fühlte sich an, als würde ich gegen das Werkzeug arbeiten.

Bis dahin habe ich den „Nachteil“ des assert.sh realisiert zu erlauben, nur entweder behauptet Exit-Status oder Ausgang ist eigentlich kein Thema, da ich gerade in test mit einer Verbindung Ausdruck wie diese

output=$($tested_script_with_args) 
status=$? 
expected_output="the expectation" 
assert_raises "test \"$output\" = \"$expected_output\" -a $status -eq 2" 
passieren kann

Da meine Bedürfnisse wirklich grundlegend waren (eine Reihe von Tests ausführen, anzeigen, dass alles gut gelaufen ist oder was fehlgeschlagen ist), mochte ich die Einfachheit von assert.sh, also habe ich das ausgewählt.

2

Nach der Suche nach einem einfachen Unit-Test-Framework für Shell, die XML-Ergebnisse für Jenkins generieren konnte und nicht wirklich etwas zu finden, schrieb ich eine.

Es ist auf SourceForge - der Name des Projekts ist Jshu.

http://sourceforge.net/projects/jshu

23

Sie fragen sich, warum niemand BATS erwähnt. Es ist up-to-date und TAP-konform.

beschreiben:

#!/usr/bin/env bats 

@test "addition using bc" { 
    result="$(echo 2+2 | bc)" 
    [ "$result" -eq 4 ] 
} 

Run:

$ bats addition.bats 
✓ addition using bc 

1 tests, 0 failures 
+1

+1 für BATS! Gemessen an den Github-Metriken (12 Mitwirkende, fast 2000 Sterne), ist dies das Tool, das die meisten Leute als bash xUnit-Test-Runner wählen. –

+1

+1: Ich habe BATS vor einer Weile zurück verwendet und war nicht völlig überwältigt. Fanden Sie dieses ausgezeichnete (unabhängig?) [Einstiegsdokument] (https://medium.com/@pimterry/testing-your-shell-scripts-with-bats-abfca9bdc5b9) heute, folgte es durch und bin jetzt völlig auf BATS verkauft . – ssc

Verwandte Themen