Während unseres Besuches bei der SoCraTes 2011 hatten mein Kollege Oliver Ochs und ich die Gelegenheit, uns zwischen vielen spannenden Sessions auch mit einem Talk zum Thema „Behavioural Driven Development (BDD) mit Jasmine“ einzubringen.
Bei Jasmine handelt es sich um ein BDD-Framework speziell für JavaScript. Manch einem mag Behavioural Driven Development bereits bekannt sein, aber für jene die es noch nicht kennen, legt die Abkürzung vermutlich schnell Analogien zu Test Driven Development (TDD) nahe. In der Tat basiert BDD auch auf Konzepten von TDD. Aber darüber hinaus liegen noch weitere Methoden wie Domain Driven Design und Akzeptanztestplanung zu Grunde. Dieser Beitrag soll die Hintergründe von Behavioural Driven Development als agile Entwicklungsmethode erläutern.
Wer sich mit testgetriebener Softwareentwicklung beschäftigt und beginnt, diese in Projekten einzusetzen, wird neben dem Erfolg, den dieser Ansatz verspricht, auch schnell auf einige Herausforderungen stoßen. Was genau muss ich testen – und wie detailliert? Wie ist der Scope meiner Tests? Wie grenze ich Tests richtig voneinander ab und wie benenne ich sie sinnvoll, damit diese Abgrenzung auch deutlich wird? Wie sollten Meldungen von Assertions formuliert sein, damit ich bei fehlschlagenden Tests schnell die Ursache finde? Auf der Grundlage dieser Fragen hat Dan North Behavioural Driven Development, kurz BDD, als eine mögliche agile Entwicklungsmethode entwickelt.
Wie der Name schon sagt, konzentriert sich Behavioural Driven Development auf „Verhalten“. Allein darunter können sich die meisten Menschen immerhin schon etwas Konkreteres vorstellen als unter dem eher abstrakten Begriff „Test“. Bei der Abstraktion von fachlichen Anforderungen kann BDD daher auch einen grossen Vorteil bieten, da Spezifikationen in natürlichsprachlicher Form von Domänenexperten erstellt werden können. Stellt man BDD und TDD gegenüber, fällt auf, dass BDD schon vom Wording in höherem Maße fachlich bzw. natürlichsprachlich orientiert ist als TDD. Dies ist bei der Kommunikation von Anforderungen mit Domänenexperten ein grosser Vorteil, da sich das Risiko von Missverständnissen aufgrund von Kommunikationslücken deutlich verringert.
In der Anwendung von BDD betrachtet man zunächst die Anwendungsfälle, aka „Use Cases“, was vom Konzept her bekannt sein dürfte. In der agilen Welt, speziell beim Einsatz von Scrum, liegen diese üblicherweise in der Form von User Stories vor. User Stories beschreiben einen klaren Mehrwert, der für bestimmte Personen durch die Umsetzung derselben entsteht. Sie werden in der Regel nach einem bestimmen Muster in natürlicher Sprache formuliert:
"Ein Barkeeper soll Drinks für die Gäste mixen."
Eine User Story definiert darüber hinaus bestimmte Akzeptanzkriterien, die erfüllt sein müssen, um zu beurteilen, ob eine Story umgesetzt ist. Genau diese Stelle adressiert akzeptanztestgetriebenes Vorgehen und versucht für diese Kriterien automatisierte Tests zu formulieren, gegen welche eine Story umgesetzt bzw. implementiert wird. Genau hier tauchen in der Regel die oben genannten Fragen auf. Da es bei Akzeptanzkriterien kein „Muster“ für die Beschreibung gibt, bleibt mitunter auch ein gewisser Interpretationsspielraum. In manchen Fällen werden Akzeptanzkriterien sogar so formuliert, dass diese eher als neue User Stories in Betracht gezogen werden sollten. Das stellt die Tester vor die Herausforderung, Tests in nachvollziehbarer Weise zu benennen, so dass sie auch bestimmten Features zugeordnet werden können. Im obigen Beispiel könnten Akzeptanzkriterien wie folgt aussehen:
-
Alle Drinks müssen anhand ihres Namens auf einer Liste auswählbar sein
-
Ein Barkeeper mixt Drinks von dieser Liste
Behavioural Driven Development greift an dieser Stelle die Idee eines bestimmten Satzmusters, ähnlich wie bei der Formulierung von User Stories, auf. Während User Stories allerdings ganz klar darauf ausgerichtet sind, den Mehrwert der Story zu verdeutlichen, konzentriert sich BDD eher auf die Akzeptanzkriterien. Da es ja um „Verhalten“ geht, wird angenommen, dass ein System sich dann richtig verhält, wenn die definierten Akzeptanzkriterien erfüllt sind. Da ein System in der realen Welt aber in verschiedenen Kontexten ausgeführt wird, sollte man dies auch bei der Formulierung von Tests berücksichtigen. Da Akzeptanzkriterien darüber in der Regel keine Aussagen machen, braucht man ein Muster, das die Formulierung des antizipierten Verhaltens auch in verschiedenen Szenarios beschreibt. Dieses Muster ist wie folgt aufgebaut
Given [context]
It [system]
Should [return result]
Dabei bricht man den eher allgemeinen Use Case auf diverse Szenarios herunter und setzt das zu testende System in verschiedene Kontexte, die sich durch konkrete Wertausprägungen voneinander unterscheiden. Damit wird das antizipierte Verhalten anhand konkreter Ausgangswerte im Ergebnis überprüfbar. Aufgrund des Kontextbezuges lassen sich auch Szenarios wesentlich einfacher voneinander abgrenzen.
Given ("an order of a wodka lemon")
It ("the barkeeper")
Should (return ["wodka lemon"])
Neben der Möglichkeit, derartige Spezifikationen zu dokumentieren, hat BDD auch zum Ziel, das spezifizierte Verhalten gegen das zu entwickelnde System automatisiert testen zu können. Die Ergebnisse einer solchen ausführbaren Spezifikation sind aufgrund der natürlichsprachlichen Eigenschaft gleichermaßen leicht zu lesen und zu interpretieren.
Barkeeper
should return wodka lemon OK
Mittlerweile exisitieren eine Reihe von Frameworks, mit deren Hilfe sich der BDD-Ansatz realisieren lässt. Zu den prominentesten Vertretern gehören RSpec für Ruby, JBehave für Java und Jasmine für JavaScript. Wie die konkrete Umsetzung des obigen Beispiels aussehen könnte, wird anhand von Jasmine im Rahmen des nächsten Blogeintrags gezeigt.