Tests lassen sich hervorragend für die Dokumentation und Spezifikation von Software nutzen. Besonders beliebt hierfür sind BDD-Frameworks wie Cucumber, die allerdings zusätzliche Komplexität mit sich bringen. Eine leichtgewichtige Alternative bietet jedoch das JGiven-Framework, das sich auch gut in eine bestehende Codebasis integrieren lässt.
Specification by Example
Behaviour Driven Development (BDD) verfolgt den Ansatz, das gewünschte Verhalten einer Software durch konkrete Nutzungsbeispiele zu spezifizieren. Daher spricht man auch häufig von Specification by Example. Diese Art der Spezifikation hat den Vorteil, dass sie automatisiert testbar ist und so die Kluft zwischen Anforderungsmanagement und Qualitätssicherung schließt. Entscheidend ist dabei, dass diese Beispiele möglichst natürlichsprachlich formuliert werden, so dass alle Stakeholder, egal ob Product Owner, Entwickler oder QA Engineer, daran mitwirken können.
Testautomatisierung durch Gherkin
Um eine Testautomatisierung zu erleichtern, werden die Beispiele meist in einem einheitlichen Schema formuliert. Am weitesten Verbreitet ist die Nutzung der Gherkin-Sprache, die Nutzungsszenarien wie folgt beschreibt.
Viele BDD-Frameworks wie beispielsweise Cucumber parsen die auf diese Weise erstellten Beispieldateien und projizieren sie auf Testanweisungen, die durch die Entwickler zuvor bereitgestellt werden müssen. Das hat den Vorteil, dass die Szenarien auch durch Personen erstellt werden können, die über keine Programmierkenntnisse verfügen. Außerdem ist die Spezifikation so vom Testframework entkoppelt. Allerdings bringt dieser Ansatz auch eine erhöhte Komplexität und mehr Wartungsaufwand durch eine zusätzliche technische Verarbeitungskomponente mit sich. Dieser Mehraufwand lohnt sich in meinen Augen nicht, wenn die Nutzungsszenarien letztendlich doch von den Entwicklern geschrieben werden oder wenn die Applikation bereits über viele Spezifikationen in Form von Unittests verfügt, die man aufwändig umschreiben müsste.
JGiven
In diesen Fällen empfiehlt es sich, Testframeworks einzusetzen, die die Gherkin-Spezifikation in Form von Testreports generieren können, um sie dann mit den Stakeholdern abstimmen zu können. Jgiven ist ein solches Framework, dass ich Euch in diesem Artikel kurz vorstellen möchte.
Ein Beispiel
Schauen wir uns das Ganze mal am Beispiel des Gilde-Rose-Kata an. Es geht dabei um eine Applikation, die einmal täglich den Warenbestand eines Ladens gemäß der Geschäftsregeln aktualisiert. Diese Funktionalität wird von der Klasse GildedRose
abgebildet, die eine Liste von Warenobjekten der Klasse Item
entgegennimmt und deren Attribute verändert.
Ziel des Katas unter anderem ist es, hierfür eine vollständige Testabdeckung zu erreichen. Als Hinweis steht uns noch eine fachliche Beschreibung der Geschäftslogik zur Verfügung, die wir als Ausgangspunkt für unsere Tests nutzen können.
Schauen wir uns zunächst mal die grundlegenden Regeln an.
- All items have a SellIn value which denotes the number of days we have to sell the item
- All items have a Quality value which denotes how valuable the item is
- At the end of each day our system lowers both values for every item
Basierend auf dieser Beschreibung können wir nun den ersten Unittest schreiben.
Wie sähe nun im Vergleich dazu der Test mit Hilfe des JGiven-Frameworks aus?
Der Test erweitert die Basistestklasse ScenarioTest
und erbt dadurch die vom Framework bereitgestellten Methoden given
, when
und then
, die die jeweiligen Gherkin-Schlüsselwörter repräsentieren. Durch ein Fluent Interface lassen sich darüber die einzelnen Testschritte aufrufen, die in der jeweiligen Phase zur Verfügung stehen. Die Methodenaufrufe selbst werden an die für die jeweilige Phase definierte Stage-Klasse weitergeleitet, die in der generischen Basisklasse des Tests angegeben wurde. In diesem Fall sind es die Klassen GivenStage
, WhenStage
und ThenStage
.
Sie alle erweitern die generische Stage
-Klasse und definieren die in Ihrer Phase zur Verfügung stehenden Testschritte als öffentliche Methoden. Da die Liste der Waren in allen drei Phasen benötigt wird, muss diese als gemeinsamer Zustand über alle Stageklassen hinweg geteilt werden. Hierfür wird diese in der GivenStage
, wo sie erzeugt wird, als Attribut mit der Annotation @ProvidedScenarioState
definiert. Während der Testdurchführung nimmt dieses Framework nun diese Liste und übergibt sie an alle Stageklassenobjekte, die über ein entsprechendes Attribut mit der Annotation @ExpectedScenarioState
verfügen.
Der Testreport
Was haben wir nun gewonnen? Der Benefit wird deutlich, wenn wir uns den generierten Bericht für diesen Test anschauen.
Im Gegensatz zum Junit-Report, bei dem wir lediglich den Methodennamen zur Testbeschreibung nutzen können, stehen uns mit JGiven alle Details des Nutzungsszenarios zur Verfügung. Hinzukommt, dass dieses natürlichsprachlich formuliert ist und so leicht mit allen Stakeholdern geteilt werden kann. Sehr hilfreich ist dabei das JGiven-Feature der parametrisierten Testschritte.
In den entsprechenden Methoden der Stageklasse können Platzhalter - in diesem Fall $
- verwendet werden, die dann im Report durch die jeweiligen Parameterwerte ersetzt werden.
Den gesamten Testreport findet Ihr hier.
Fazit
Tests eignen sich nicht nur zur Qualitätssicherung, sondern können auch als lebende Dokumentation genutzt, bis hin zur Erfüllung von Tracebility-Anforderungen im Projekt. Das JGiven-Framework unterstützt Euch dabei, ohne Aufwand für eine zusätzliche Adapterschicht. Es lässt sich so auch einfach nachträglich in eine bereits bestehende Codebasis integrieren.