Ausführbare Spezifikationen (und eine Portion BDD)

© S&S_Media
In einer der letzten Folgen haben wir bereits über beispielhafte Spezifikationen geschrieben. Diesmal möchten wir konkreter auf die Möglichkeiten der Ausführbarkeit solcher Spezifikationen eingehen. Dazu werden wir einen Ausflug in die großartigen Möglichkeiten von Behavior-driven Development unternehmen.
Diesen Begriff hat Dan North schon 2006 geprägt, als Reaktion auf immer wiederkehrende Probleme mit Test-driven Development. Sein einfacher, aber genialer Vorschlag zur Verbesserung von TDD lautete: „Die Namen von Testmethoden sollten umgangssprachliche Sätze sein“. In Kurzform: BDD versucht, Test-driven Development, einige Aspekte von Domain-driven Design sowie Techniken des automatisierten Akzeptanztests miteinander zu verbinden, um Entwicklungsteams, Fachleute und andere Stakeholder mit einer gemeinsamen Sprache auszustatten.
Klingt erstmal wie reinstes Marketingdeutsch – enthält aber viel Wahrheit. Unsere Recherchen zum aktuellen Stand von BDD und den zugehörigen Tools haben bei uns einen sehr positiven Eindruck hinterlassen.
In BDD geht’s um Spezifikation
Fangen wir einmal vorne an. Wir wollen doch alle (Entwicklungsteams inklusive ArchitektInnen, Product Owner, Requirements Engineers, Tester und andere) zuerst einmal verstehen, was unser System denn genau tun soll. Natürlich iterativ und in kleinen Portionen, weil sich viele Dinge und Erkenntnisse erst während der Entwicklung ergeben. Dieses „Was-das-System-genau-tun-soll“ bildet den Kern von BDD. Es geht um das Verhalten des Systems, um das genaue Verständnis, was die wesentlichen Stakeholder denn von dem System erwarten und warum. Es geht nicht(!) primär um automatisch ausführbare Testfälle, sondern eben erstmal um ein angemessen präzises Verständnis von Anforderungen – was auch der Grund ist, weswegen wir das Thema in dieser Kolumne aufgreifen.
BDD arbeitet Top-Down
Ähnlich wie wir das zu Beginn unserer Req4Arcs-Kolumne vorgeschlagen haben, fordert auch BDD, bei der Spezifikation mit einer strategischen Zielsetzung (auch Vision genannt) zu beginnen, damit wir als Entwicklungsteam wissen, wohin die Reise insgesamt führen soll [1]. Anschließend brechen wir beim BDD diese Anforderungen auf sogenannte Features herunter, die wir dann wiederum durch Beispiele konkretisieren. Erst diese Beispiele versuchen wir dann bei Bedarf zu automatisieren. John Ferguson Smart [2] hat dafür eine sehr feingranulare Hierarchie vorgeschlagen, die Sie (auszugsweise)in Abbildung 1 finden.
An dieser Stelle interessieren uns die eher konkreten Teile dieser Pyramide beginnend bei den sogenannten Features. Die zu finden, stellt manchmal schon eine ordentliche Herausforderung dar, bei deren Überwindung uns unter anderem die Methode Impact Mapping (Kasten: „Impact Map“) helfen kann. Außerdem haben wir in den zurückliegenden Folgen mehrmals über funktionale Anforderungen geschrieben – auch da werden Sie fündig. Gehen wir also hier optimistisch davon aus, dass Sie mit Ihrer Lieblingsmethodik vernünftige und zum Gesamtziel beitragende Features finden. Die priorisieren Sie natürlich anhand der bekannten Geschäftsziele – aber das kennen Sie als treue LeserIn unserer Kolumne ja bereits. Die offene Frage lautet: „Wie können wir die jetzt ausführbar machen?“
Impact Map – von Zielen zu Features
Gojko Adzic hat 2012 unter dem Namen Impact Mapping eine Methode vorgestellt, um die Beziehung zwischen den einem System zugrunde liegenden Unternehmenszielen, den betroffenen Akteuren und den Features, mit deren Hilfe das System die erwarteten Ergebnisse liefern kann, zu visualisieren. Impact Maps sind einfach zu erstellen und leicht zu verstehen und können ein sehr nützliches Werkzeug zur Dokumentation solcher Unternehmensziele und der Validierung von Annahmen sein. Das macht Impact Maps zu einem kreativen Werkzeug, auf das wir in einer zukünftigen Folge dieser Kolumne noch etwas genauer eingehen werden. Hier schon mal ein kleiner Ausblick und ein Beispiel:
Eine Impact Map ist eine Art Mindmap, die während der Konversation verschiedener Stakeholder (u. a. Manager, Fachexperten und Entwicklungsteam) erstellt wird. Das Gespräch dreht sich um vier Arten von Fragen:
- Warum? Was ist das zugrunde liegende Unternehmensziel, das wir erreichen wollen?
- Wer ist betroffen als User oder sonstiger Stakeholder?
- Wie können Stakeholder zu dem Ziel beitragen? (Dieses „Wie“ ist der Impact, der Namensgeber der Methode. In der Pyramide aus Abbildung 1 sind das die Capabilities, die Fähigkeiten unseres Systems.)
- Was kann das System tun? (Die „Was“-Antworten sind oftmals gute Kandidaten für unsere Features, die wir dann ja letztlich automatisieren wollen – sowohl als ausführbare Spezifikation wie auch natürlich als Teile unseres Systems.)
Das Beispiel aus Abbildung 2 stammt aus [2] und illustriert aus unserer Sicht diese Ansätze ganz gut.
Konkretisierung nach Schema F
Unsere Features werden oftmals noch als relativ abstrakte Wünsche oder Zielvorstellungen ausgedrückt, insbesondere ohne Implementierungsdetails. Diese fügen wir in den Verfeinerungen (üblicherweise Stories oder Szenarien genannt) hinzu, dann jeweils mit klar formulierten Akzeptanzkriterien. Letzteres klingt schon ein wenig nach Automatisierung, besonders wenn wir den BDD-Vorschlägen folgen und unsere Stories oder Beispiele gemäß der einfachen Syntax der Sprache Gherkin (Kasten: „Gherkin kompakt“) formulieren. Gherkin-Szenarien bestehen aus dem Dreisatz Given-When-Then. Ein Beispiel inklusive dem dazugehörigen Feature finden Sie in Listing 1.
Feature: Team Scoring Teams starts with zero score Correct answer gets points depending on how difficult it is Scenario: Score starts at zero Given I register a team Then my score is zero Scenario: Correct easy answer scores 10 Given I register a team When I submit a correct easy answer Then my score is 10 Scenario: Correct hard answer scores 50 Given I register a team When I submit a correct hard answer Then my score is 50
Die Syntax der Sprache Gherkin (englisch für Essiggurke) wird von einigen Werkzeugen der Cucumber-Familie [7] (englisch für Gurke) implementiert. Was „Gurken“ mit Anforderungen oder Akzeptanztests zu tun haben, ist eine nette (private) Geschichte, des ursprünglichen Entwicklers Aslak Hellesøy – Sie können sie auf Quara selbst einmal nachlesen.
Interessant ist noch, dass die Schlüsselworte der Sprache Gherkin neben dem ursprünglichen Englisch in viele (>50) andere natürliche Sprachen übersetzt worden sind, damit Fachleute überall auf der Welt in ihrer eigenen Sprache Features und Szenarien mit BDD konkretisieren können. Hier im Artikel bleiben wir aber mal bei Englisch.
Gherkin kompakt
Gherkin bezeichnet die DSL diverser BDD-Tools und verfolgt zwei Ziele: einerseits eine hohe Verständlichkeit für Businessstakeholder und andere Nicht-ITler, andererseits eine einfache Automatisierbarkeit mit BDD-Tools. Gherkin bildet damit eine gemeinsame Sprache für sowohl Anforderungen als auch automatisierte Tests.
Gherkin bezeichnet die DSL diverser BDD-Tools und verfolgt zwei Ziele: einerseits eine hohe Verständlichkeit für Businessstakeholder und andere Nicht-ITler, andererseits eine einfache Automatisierbarkeit mit BDD-Tools. Gherkin bildet damit eine gemeinsame Sprache für sowohl Anforderungen als auch automatisierte Tests.
In Gherkin schreiben Sie Anforderungen in natürlicher Sprache und folgen dabei einer spezifischen Struktur. Jedes Szenario besteht aus einer Folge von Schritten (Steps), die jeweils mit einem der Schlüsselworte Given, When, Then, And oder But beginnen. Ja, das geht auch auf Deutsch, obwohl wir hier im Artikel Englisch verwenden. Die Reihenfolge ist immer Given-When-Then:
- Given (gegeben sei, angenommen): Vorbedingung, bestimmte Situation oder Sachverhalt
- When (wenn): ein bestimmtes Ereignis, das eintritt, oder eine Aktion, die stattfindet
- Then (dann): das erwartete Ergebnis
- And (und) und But (aber) können Sie verwenden, um jeden der drei Teile etwas lesbarer zu formulieren
Mehrere ähnliche Szenarien können Sie mit Hilfe von Tabellen deutlich kompakter schreiben (Spock Framework nennt das Data-driven), beispielsweise:
Scenario Outline: Earning interest Given I have an account of type with a balance of When the monthly interest is calculated Then I should have earned at an annual interest rate of And I should have a new balance of
Ihr freundliches BDD-Framework (etwa Cucumber) würde das Szenario für jede Zeile der Tabelle einmal ausführen und die Werte der Variablen in ersetzen. Bleibt noch zu sagen, dass es für viele IDEs (IntelliJ, Eclipse, Atom, VS Code) mittlerweile sehr guten Gherkin-Support gibt.
Vom Szenario zur Ausführung
Zur Ausführung unserer Szenarien setzen wir jetzt Frameworks wie Cucumber, JBehave oder Spock ein. In Abbildung 3 sehen Sie die Zusammenhänge im Überblick. Beginnen wir mit Cucumber (wobei diese Erläuterungen fast identisch auch für JBehave oder das SpecFlow-Framework im .NET-Umfeld gelten). Cucumber kann unser Team-Scoring-Feature von oben schon ausführen, beschwert sich allerdings über „undefined steps“. Logisch, denn bislang fehlt unseren Given-When-Then Szenarien ja noch immer die Verbindung zum Quellcode unseres Systems.
Dazu schreiben wir für Cucumber so genannte Step-Definitions, die unsere textuellen Beschreibungen im .feature
-File interpretieren. Das sieht dann wie folgt aus:
@Given("I register a team") public void i_register_a_team() { // Anwendungscode... }
In der @Given
-Annotation wiederholen wir den Text aus der Given-Klausel unseres Szenarios. Diese Source steht in einer normalen Java- oder Groovy-Klasse – in der wir natürlich auch Variablen für unser Team, den Score oder andere schicke Dinge deklarieren können, respektive unseren eigentlichen Quellcode aufrufen. Sie raten jetzt richtig: Es gibt ebenfalls die Annotationen @When
und @Then
, die analog funktionieren.
Diese Kolumne kann und möchte lediglich einen Überblick über die Möglichkeiten ausführbarer Spezifikationen geben – für eine gründliche Einführung schauen Sie in [1] oder auf auf der cucumber.io-Webseite.
Spock und BDD
Einer von uns Autoren (Gernot) ist erklärter Fan von Spock und hat eine Menge Code Test- und/oder Specification-driven mit Hilfe dieses großartigen Werkzeugs entwickelt. In Abbildung 3 finden Sie Spock zusammen mit dem klassischen JUnit als Möglichkeit, Low-Level-Spezifikationen zu schreiben, da Spock mit Fokus auf codenahe Stakeholder entwickelt wurde und nicht wie Gherkin den Fokus auf Businessstakeholder richtet. Spock-Spezifikationen sind bezüglich des Kodieraufwands wesentlich einfacher und schlanker als Gherkin-Features mit ihren (eigenständigen respektive zusätzlichen) Step-Definitionen. Andererseits können wir uns kaum Businessstakeholder vorstellen, die (freiwillig) Spock-Spezifikationen lesen und schreiben würden, denn sie lesen sich ähnlich codelastig wie die Step-Definitionen von Cucumber.
Falls Sie als Entwickler jedoch spezifizieren möchten, dass in einer bestimmten Situation eine Exception eines bestimmten Typs geworfen wird (oder auch nicht), dann ist Spock bestimmt die eleganteste und einfachste Art, das zu tun. Daher nimmt Spock in der von Gherkin dominierten BDD-Welt eine wichtige Rolle ein – und wir empfehlen es besonders für JVM-basierte Systeme wärmstens.
Ausblick
Es geht, wie so oft, noch einen kleinen Schritt weiter. Die ausgeführten Spezifikationen werden durch JUnit-ähnliche Runner ausgeführt – und von denen können wir einen Report generieren lassen: Diesen Ansatz finden wir als Living Documentation etwa in Serenity frei verfügbar umgesetzt. Die Ergebnisse haben uns stark beeindruckt und können bestimmt auch Ihnen in ihrer (schweren!) täglichen Architektur- und Entwicklungsarbeit helfen!
Fazit
Behavior-driven Development ist für unsere Architektenrolle wirklich interessant und gewinnbringend: Brechen Sie (mit Hilfe Ihrer Stakeholder) funktionale Anforderungen auf Fähigkeiten und Features herunter und diese dann auf Szenarien (aka Stories), wobei Sie von den (High-Level-)Geschäftszielen ausgehen. Mit ein wenig zusätzlichem Glue Code (in der JVM-Welt: Cucumber/Gherkin, JBehave oder Spock) bekommen Sie auf diese Weise ausführbare Spezifikationen mit ordentlichen Akzeptanzkriterien. Die Krönung: „Lebendige Dokumentation“, die sich mit jeder Ausführung Ihrer Spezifikationen neu generiert, ist ein garantiert aktueller Überblick darüber, welche Features gerade funktionieren und wo es Probleme gibt.
Wer die letzten Folgen unserer Kolumne gelesen hat, wird direkt an manche noch fehlenden Qualitätsanforderungen denken, aber mit Hilfe der ausführbaren Spezifikationen gemäß BDD können wir schon mal einen ganz ordentlichen Teil von Anforderungen erfassen und kontinuierlich testen. Insofern können Sie loslegen, ein paar Szenarien für Ihr aktuelles System schreiben und von einem der BDD-Tools mal ausführen lassen. In diesem Sinne: Bis zur nächsten Folge, und möge die Macht ausführbarer Specs mit Ihnen sein!
[1] Smart, John F.: „BDD in Action“; Manning, 2014. Auch 2019 noch unbedingt lesenswert. Der Autor, John Smart, ist auch Schöpfer und treibende Kraft hinter Serenity.
Hinterlasse einen Kommentar