Lebende BDD-Testspezifikation mit Gherkin

Behavior Driven Development (BDD) ist eine agile Software-Entwicklungstechnik, ähnlich der allgemein bekannten Technik der Testgetriebenen Entwicklung (TDD). Bei BDD gilt wie auch bei TDD die goldene Regel: „Test First!“ Erst schreiben wir den Test, dann setzen wir die entsprechende Implementierung iterativ um. Im Gegensatz zu TDD wird bei BDD die Spezifikation jedoch nicht mit Hilfe eines Unit Test Frameworks einer Programmiersprache verfasst.  Der Clou bei BDD: Die Testspezifikation beschreibt das Verhalten des Programms in natürlicher Sprache!
So können auch Nicht-Programmierer Tests für diese Software schreiben.

Natürlich können die BDD-Tests nicht ganz formlos niedergeschrieben werden. Die Testbeschreibungen müssen sich an eine gewisse Vorlage halten, ähnlich wie bei User Stories (As a role, I want product to do foo when I do bar). Ein Beispiel für diese Grammatik ist Gherkin.

Mit Gherkin werden die einzelnen Testschritte zeilenweise definiert und diese Schritte beginnen mit bestimmten Schlüsselwörtern:

Dude mit Checkliste für den Artikel zu BDD Testspezifikation

  • Mit Given kann eine Voraussetzung definiert werden.
  • When definiert eine Tätigkeit.
  • Then definiert einen Verifikationsschritt.

Mehrere Testschritte beschreiben ein Szenario. Mehrere Szenarien bilden zusammen ein „Feature“.

Das klassische Beispiel ist eine To-do-Listen-Applikation, in einer Datei namens todolist.feature:

Feature: Tests for a simple TODO list application

Scenario: Adding an item to an empty TODO list creates a new entry
Given the TODO list is empty
When I add a new list entry „Gurke“
Then the TODO list contains 1 entry

Für Entwicklerinnen & Entwickler

Wie eingangs erwähnt, können wir eine BDD-Testspezifikation ohne Programmierkenntnisse verfassen. Ganz ohne Code geht es dann aber doch nicht. Die Entwicklerinnen und Entwickler füllen die einzelnen Gherkin-Testschritte mit Leben, d.h. mit Code hinterlegt. Hierfür existieren für die meisten Programmiersprachen sogenannte Gherkin-Runner.
In unseren Projekten verwenden wir häufig den Python Gherkin-Runner behave.

Ein Beispiel für eine Testschritt- bzw. Step-Implementierung (steps.py) in Python mit behave sieht wie folgt aus:

@given("the TODO list is empty")
def step_impl(context):
    context.todo_list = TodoList()
    assert context.todo_list == 0

Also eine normale Funktion mit einem speziellen „Decorator“. behave liest das Feature File ein, führt die dazugehörigen Python-Testschritte aus und erstellt einen Testreport. Der Aufruf informiert natürlich auch über eventuell fehlgeschlagene Schritte.

Einige BDD-Runner für bestimmte Frameworks, wie zum Beispiel Flutter, bieten vordefinierte „Steps“ an, die häufig verwendet werden.

Für Testerinnen & Tester & Requirements Engineers

Testerinnen und Tester können nun mit BDD entsprechend neue Szenarien definieren, wie sich die Software verhalten soll, ohne sich in eine Programmiersprache einarbeiten zu müssen. Idealerweise ist nach einiger Zeit die Menge an bereits implementierten Testschritten sehr umfangreich. Neu geschriebene Szenarien benötigen dann keine Erweiterungen mehr und die neuen Tests laufen direkt „grün“.

Lebendige Testspezifikation

Die Tatsache, dass mit BDD und Gherkin die Testspezifikation in einer natürlichen Sprache geschrieben wird, sollte man sich zunutze machen! Es wäre doch schade, wenn nur die Entwicklerinnen und Entwicklern und die Continuous Integration regelmäßig die Tests „lesen“.

Warum also nicht die Feature-Dateien in ein Dokument gießen? Und das alles automatisch, als Teil der CI-Pipeline, so dass man stets eine aktuelle Version der Testspec zur Hand hat. Diese kann man zur Not auch manuell ausführen.

In unseren Projekten haben wir gute Erfahrungen mit Sphinx gemacht, um Dokumentation zu erstellen. Für Sphinx gibt es auch ein entsprechendes Gherkin-Plugin. Aber auch für viele andere Dokumentationssysteme gibt es den passenden Gherkin-Converter (z.B. ascii doctor).

Das Prinzip hinter dem Plug-in ist einfach. Es nimmt die Feature-Dateien und wandelt sie in ein Format um, mit dem Sphinx umgehen kann: „Restructured Text“ (RST). Die Schlüsselwörter werden dabei besonders hervorgehoben. Unser obiges Beispiel der Todo-Listen-App sieht dann wie folgt aus:

:gherkin-feature-keyword:`Feature:` :gherkin-feature-content:`Tests for a simple TODO list application`
=======================================================================================================

:gherkin-scenario-keyword:`Scenario:` :gherkin-scenario-content:`Adding an item to an empty TODO list`
------------------------------------------------------------------------------------------------------

| :gherkin-step-keyword:`Given` the TODO list is empty
| :gherkin-step-keyword:`When` I add a new list entry \"Gurke\"
| :gherkin-step-keyword:`Then` the TODO list contains 1 entry

Sphinx wandelt diese Datei in ein entsprechendes PDF- oder HTML-Dokument um und stellt sie als CI-Artefakt zur Verfügung.

Wenn die bestehenden Tools nicht den Ansprüchen genügen, ist eine weitere Möglichkeit, mit einem Gherkin-Parser und einer Template-Engine (z.B. Python jinja) ein eigenes Script zu schreiben. Dieses Script wandelt Feature Files in entsprechende Markup-Dateien um.

Traceability

Üblicherweise wollen wir aus regulatorischen Gründen eine Verknüpfung zwischen Anforderungen (Requirements) und Testfällen herstellen (Traceability). Eine Möglichkeit, dieses mit Gherkin-Bordmitteln zu lösen, sind sogenannte Tags. Szenarien können mit @tagname markiert bzw. kategorisiert werden. Diese Tag-Namen sind frei wählbar. So ist es möglich, ein Szenario mit der Anforderungs-ID des verwendeten Anforderungsmanagement-Tools zu markieren.

@JIRA-4711
@myreqtool-0042
Scenario: Do stuff
Given ...
When ...
...

Auch hier besteht die Möglichkeit zur Automatisierung. Der Gherkin-Runner kann zum Beispiel nur die Szenarien ausführen, die eine bestimmte Anforderung abdecken: behave --tags '@JIRA-4711'

Mit relativ wenig Aufwand ist es möglich, mit Hilfe eines Scripts bzw. Gherkin-Parsers die entsprechenden IDs eines Feature Files auszulesen und zum Beispiel eine Traceability Matrix zu erstellen.

Fazit

BDD-Tests bieten viele Vorteile: eine menschenlesbare (und schreibbare!) Spezifikation, die automatisch ausgeführt und mit Hilfe entsprechender Werkzeuge in ein Dokument überführt werden kann. Auch weitere Auswertungen, wie zum Beispiel Anforderungsüberdeckung, sind möglich. Diese Form der Testentwicklung und -dokumentation (zusätzlich zur Praxis des TDD) ist in vielen unserer Projekte zum festen Bestandteil geworden.