2016-03-25 6 views
5

Ich bin in unit testing von einigen legacy Shell-Skripten.Shell Script Unit-Test: Wie man ein komplexes Hilfsprogramm malt

in dem realen Welt-Skripte werden häufig Programme enthalten eine Menge von Optionen wie find, tar, cpio, grep, sed, rsync, date und so weiter mit einem paar ziemlich komplexen Befehlszeilen nennen Dienstprogramm verwendet. Manchmal werden reguläre Ausdrücke oder Platzhaltermuster konstruiert und verwendet.

Ein Beispiel: mit dem Dienstprogramm rsync Ein Shell-Skript, das in der Regel durch cron in regelmäßigen Abständen aufgerufen wird, hat die Aufgabe, von einem Computer zum anderen einige großen Verzeichnisbäume zu spiegeln.

#!/usr/bin/env bash 
    ... 
    function mirror() { 
     ... 
     COMMAND="rsync -aH$VERBOSE$DRY $PROGRESS $DELETE $OTHER_OPTIONS \ 
        $EXCLUDE_OPTIONS $SOURCE_HOST:$DIRECTORY $TARGET" 
     ... 
     if eval $COMMAND 
     then ... 
     else ... 
     fi 
     ... 
    } 
    ... 

Als Michael Feathers schrieb in sein berühmten Buch Working Effectively with Legacy Code, ein guter Unit-Test läuft sehr schnell und nicht das Netz berührt, die File-: Mehrere Arten von Dateien und Verzeichnissen sollen von der Spiegelung ausgeschlossen werden System oder öffnet eine beliebige Datenbank.

Nach Michael Feathers Rat die Technik hier zu verwenden ist: dependency injection. Das zu ersetzende Objekt ist das Dienstprogramm rsync.

Meine erste Idee: In meinem Shell-Skript-Test-Framework (ich benutze bats) Ich $PATH in einer Art und Weise zu manipulieren, dass ein mockuprsync statt das reale rsync Dienstprogramm gefunden wird. Dieses mockup-Objekt könnte die angegebenen Befehlszeilenparameter und -optionen überprüfen. Ähnlich wie andere Dienstprogramme, die in diesem Teil der script under test verwendet werden.

Meine früheren Erfahrungen mit realen Problemen in diesem Bereich des Skripts waren oft Fehler, die durch Sonderzeichen in Datei- oder Verzeichnisnamen, Probleme mit Zitaten oder Codierungen, fehlende ssh-Schlüssel, falsche Berechtigungen und so weiter verursacht wurden. Diese Art von Bugs wäre dieser Technik des Komponententests entgangen. (Ich weiß: Für einige dieser Probleme ist der Komponententest einfach nicht die Lösung).

Ein weiterer Nachteil ist, dass das Schreiben einer mockup für ein komplexes Dienstprogramm wie rsync oder find ist fehleranfällig und eine langwierige Engineering-Aufgabe für sich.

Ich glaube, die oben beschriebene Situation ist allgemein genug, dass andere Menschen ähnliche Probleme haben könnten. Wer hat ein paar clevere Ideen und würde sie gerne hier mit mir teilen?

+3

Nach Unit-Tests, müssen Sie Systemtests. Erstellen Sie vielleicht ein einfaches Testnetzwerk mit jeweils einer problematischen Datei, Verzeichnissen, fehlenden Schlüsseln usw. – tripleee

+1

Verwenden Sie 'tee' inline mit einem realen Szenario, um aufgerufene Befehlsantworten zu erfassen, und verwenden Sie dann diese Dateien zur Wiedergabe im testgespannten Szenario vielleicht mit einem Skript, das die empfangenen Argumente protokolliert und blind die vordefinierte Antwort aussendet. –

+0

@Keith Tyler: Das ist eine wirklich nette Idee: Offensichtlich erfordert diese Technik eine Art Systemtest, der vorher geschrieben wurde (aber wenn man anfängt, an einem Legacy-Skript zu arbeiten, ist es zumindest gut, zumindest einen solchen Test zu schreiben, bevor man mit dem Refactoring beginnt Idee). Daumen hoch für diesen Vorschlag. – pefu

Antwort

1

Cargill Dilemma:

„Jedes Design Problem kann durch das Hinzufügen einer zusätzlichen Dereferenzierungsebene gelöst werden, mit Ausnahme der zu viele Dereferenzierungsebenen“

Warum System Befehle vortäuschen? Schließlich, wenn Sie Bash programmieren, ist das System Ihr Ziel und Sie sollten Ihr Skript mit dem System auswerten.

Komponententest, wie der Name schon sagt, gibt Ihnen ein Vertrauen in einen einheitlichen Teil des Systems, das Sie entwerfen. So müssen Sie definieren was ist Ihre Einheit im Falle eines Bash-Skript.Eine Funktion ? Eine Skriptdatei? Ein Kommando ?

Given wollen Sie das Gerät als Funktion definieren ich dann eine Liste von bekannten Schreibfehler würde vorschlagen, wie Sie oben aufgelistet:

  • Sonderzeichen in Datei- oder Verzeichnisnamen
  • Probleme mit Zitate oder Kodierungen
  • Fehlende SSH-Schlüssel
  • Falsche Berechtigungen und so weiter.

Und schreiben Sie einen Testfall dafür. Und versuchen Sie nicht, von den Systembefehlen abzuweichen, denn sie sind Integral Teil des Systems, das Sie liefern.

0

Sie können jeden Befehl Mockup eine Funktion, wie dies mit:

function rsync() { 
    # mock things here if necessary 
} 

Dann die Funktion exportieren und den Unittest auszuführen:

export -f rsync 
unittest