Über unsMediaKontaktImpressum
Dominique Petrich 12. Juni 2025

Softwareentwicklung optimieren mit Cucumber

BDD, TDD und bessere Zusammenarbeit

In diesem Artikel werde ich einen detaillierten Blick auf Cucumber werfen, ein leistungsstarkes Testautomatisierungswerkzeug, das weit über die bloße Automatisierung von Tests hinausgeht. Als Open-Source-Tool bietet Cucumber die Möglichkeit, unseren agilen Softwareentwicklungsprozess durch die Integration von zwei bewährten Methoden – Behavior Driven Development (BDD) und Test Driven Development (TDD) – erheblich zu erweitern und zu optimieren.

BDD fokussiert sich auf das Verhalten der Software aus der Sicht der Anwender:innen, während TDD darauf abzielt, Tests vor der eigentlichen Implementierung zu schreiben, um die Qualität des Codes von Anfang an sicherzustellen. Im Verlauf dieses Artikels werde ich beide Methoden erläutern und deren Vorteile für die agile Entwicklung darlegen.

Ein wesentlicher Aspekt von Cucumber ist die Verbesserung der Zusammenarbeit innerhalb des Teams. Durch die Verwendung von beschreibbaren Tests in leicht verständlicher und natürlicher Sprache fördert Cucumber die Kommunikation zwischen technischen und fachlichen Teammitgliedern. Dies führt nicht nur zu einer besseren Teamdynamik, sondern auch zu einer effizienteren fachlichen Dokumentation.

Es ist wichtig zu erwähnen, dass die Prinzipien von BDD und TDD auch ohne Cucumber anwendbar sind und es ähnliche Werkzeuge auf dem Markt gibt. Dennoch bietet Cucumber einzigartige Funktionen, die es zu einer bevorzugten Wahl für viele Entwicklungsteams machen. Dieser Artikel ist daher nicht nur ein Erfahrungsbericht, sondern auch eine Einladung, die Möglichkeiten von Cucumber und dessen Integration in den agilen Softwareentwicklungsprozess zu erkunden.

Ich werde die grundlegenden Konzepte von BDD und TDD erläutern, die Funktionsweise von Cucumber näherbringen und Einblicke in die technische Integration des Tools geben. Zudem werde ich praktische Beispiele vorstellen, die die Anwendung von Cucumber in realen Projekten veranschaulichen.

Letztendlich zielt dieser Artikel darauf ab, ein umfassendes Verständnis für die Nutzung von Cucumber als Testautomatisierungswerkzeug zu vermitteln und aufzuzeigen, wie wir durch die Integration von BDD und TDD unseren agilen Softwareentwicklungsprozess optimieren können.

BDD – Behavior Driven Development

Bei Behavior Driven Development (BDD) handelt es sich um eine Methode der agilen Softwareentwicklung. Im Grunde bedeutet BDD die Formulierung einer Anforderung und Softwarebeschreibung aus Anwendersicht. Dies geschieht in der Regel vor der eigentlichen Implementierung (Entwicklung).

BDD bedient sich bei der Formulierung der Anforderung und Testfälle einer festen Syntax. Diese orientiert sich an Given, die Vorbedingung, When, die Aktion und Then, das erwartete Ergebnis. Diese einheitliche Sprache (Syntax) verspricht eine bessere Zusammenarbeit und Kommunikationsfähigkeit im Team und senkt dadurch die Kosten. Zusätzlich fördert BDD die Testautomatisierung und erleichtert diese.

Das Risiko bei der Nutzung von BDD liegt bei einer fehlenden Wartung der Testfälle. Die Formulierungen und Testfälle in der Anforderung und Testautomatisierung müssen aktualisiert und hinterfragt werden. So vermeidet man eine vermeintliche Sicherheit bezüglich der Testabdeckung. Zusätzlich ist es enorm wichtig, die Anwender:innen, aus deren Sicht die Anforderung und Testfälle formuliert werden, richtig zu verstehen. Ist dies nicht gegeben, wird die Anforderung fehlerhaft umgesetzt und meine Testfälle werden es auch.

Dieses Beispiel zeigt die Beschreibung einer Fachlichkeit bzw. deren Testfälle in der Syntax von BDD. Die Fachlichkeit, welche hier getestet wird, ist der Login. 

Im ersten Testfall befindet man sich auf der Login-Seite und gibt dann, als Aktion, die Daten ein und klickt auf Login. Nun erwartet man im Ergebnis die Öffnung des Kundenkontos. Man folgt hier der erwähnten Syntax – Given (Vorbedingung), When (Aktion) und Then (Ergebnis).

Der zweite Testfall beschreibt den Negativtestfall. Hier gibt man fehlerhafte Daten in der Aktion (When) ein. Nun erwartet man im Ergebnis (Then) eine Fehlermeldung.

TDD – Test Driven Development

Test Driven Development (TDD) ist eine weitere Methode in der agilen Softwareentwicklung und nutzt beziehungsweise ist "Test First". Test Driven und Test First bedeutet ganz einfach, dass man als erstes die Testfälle schreibt, und zwar bevor man die eigentliche funktionale Implementation vornimmt. Bei Test Driven Development verfolgt man einen iterativen Prozess.

Als erstes schreibt man, wie erwähnt, die Testfälle (Test First). Diese laufen noch nicht erfolgreich und schlagen fehl. Nun beginnt man mit der funktionalen Entwicklung der Anforderung und versucht so, die fehlgeschlagenen Tests nach und nach "grün", also erfolgreich zu gestalten. Nachdem die Testfälle alle erfolgreich laufen und die Anforderung somit erfolgreich entwickelt ist, folgt der dritte Schritt des iterativen Vorgehens in TDD. Es findet ein Refactoring des Codes und der Tests statt. Hier wird strukturiert, modularisiert und schlicht aufgeräumt.

Test Driven Development (TDD) sorgt für eine sichere Erfüllung der Anforderungen. Zusätzlich reduziert TDD die Wahrscheinlichkeit von Fehlern. Insgesamt sorgt das iterative Vorgehen inklusive des Refactorings für eine bessere Software- und Codequalität. Der Code ist strukturiert, modularisiert und wartbar.

Was ist Cucumber?

In diesem Artikel handelt es sich bei Cucumber nicht um Gurken. Cucumber ist ein Werkzeug, welches die Möglichkeit bietet, Behavior Driven Development (BDD) und Test Driven Development (TDD) in die Arbeitsweise und Testautomatisierung zu integrieren. Cucumber ist ein Open-Source-Testautomatisierungs-Tool, welches ursprünglich von SmartBear entwickelt wurde. Die Syntax, also die einheitliche Sprache in Cucumber, ist Gherkin. Diese erläutere ich im Anschluss. Cucumber unterstützt viele Programmiersprachen, wie beispielsweise Java, Scala, Javascript, Python.

Technische Integration

// Dependency in build.sbt
„io.cucumber“ && „cucumber-scala“ & cucumberVersion % Test,

// Create TestDefinition class
import io.cucumber.scala.Implicits._

class BasicStepDef extends ScalaDsl with EN with Matchers {
…

// Implement test execustion functions
…

Um Cucumber in ein Entwicklungsprojekt zu integrieren, kann man einfach entsprechende Dependency in das Projekt ziehen. Die Beispiele dieses Artikels sind aus Scala mit sbt, da wir diese in meinem Team im Einsatz haben. Die Automatisierung der Testfälle, welche in der Gherkin-Syntax (BDD) geschrieben sind, geschieht in einer Test Definition Class. Hier hinterlegt man zu den einzelnen Testschritten funktionalen, lauffähigen Code.

Given("""^Die Storefront wird von einem Lasttest mit UserAgent '(.+)' aufgerufen$""") { userAgent: String =>
  userAgent match {
    case "monitor" =>
      callProcessor(TrackingMessageFixture.storefront().withUserAgent("monitor"))
    case "loadtest" =>
      callProcessor(TrackingMessageFixture.storefront().withUserAgent("loadtest"))
  }
}

// Header

Given("""^Besucher startet auf der Storefront mit folgenden Headern:?$""") { (dataTable: DataTable) =>
  {
    val headers = dataTableAsTuple2(dataTable, "key", "value")
    val input = TrackingMessageFixture.storefront().withHeaders(headers.head, headers.tail: _*)
    callProcessor(input)
  }
}

Given("""^Besucher startet auf der Storefront ohne folgende Header:?$""") { (dataTable: DataTable) =>
  {
    val headers = dataTableAsMap(dataTable)
    callProcessor(TrackingMessageFixture.storefront().withoutHeaders(headers))
  }
}

Dieses Beispiel zeigt einen Auszug aus der Test Definition Class. Der Testschritt in der Mitte ("//Header" bis "Given") repräsentiert eine Formulierung nach BDD in Gherkin. Hier findet nun die funktionale Implementation zur Testautomatisierung statt. Ich empfehle einen strukturierten Aufbau der Test Definition Class zur einfacheren Auffindbarkeit und zusätzlich eine möglichst generalisierte Formulierung der Testschritte, um diese wiederverwendbar zu haben. Eine Test Definition Class kann mit der Anzahl der Testfälle bzw. der zu testenden Fachlichkeiten lang werden.

Das Beispiel kann durch die wiederverwendbare Formulierung in allen Testschritten genutzt werden, in denen Header verwendet werden. Die Implementation ermöglicht eine unbestimmte Anzahl an Header mit oder ohne Values.

// write test cases in feature file
// drinkBeer.feature

Feature: how to drink beer
Description

	Scenario: 1 drink some beer

		Given bottle beer in my hand
		When put bottle to mouth
		Then drink beer

	Scenario: 2 …

Um die Testfälle nach Behavior Driven Development (BDD) in der festen Gherkin Syntax zu schreiben, benötigt man sogenannte "Feature Files". In einem Feature File werden eine Fachlichkeit beschrieben und die Testfälle dazu formuliert.

Gherkin-Syntax in Cucumber

Für die Integration von Behavior Driven Development (BDD) benötigt man eine einheitliche Sprache (Syntax). Diese nutzt man für die Formulierung der Anforderung und Testfälle. Die Syntax von Cucumber nennt sich Gherkin.

Syntax: Gherkin

Feature: Funktionalität / Fachlichkeit
Scenario: Testfall
Scenario Outline: Testfall mit mehreren Ausprägungen

Testschritte:
Given
When
Then
And
But

@Tags: Filter & Feature Toggle

Ich schrieb bereits, dass eine Fachlichkeit in Feature Files getestet wird. Ein Feature beschreibt in Gherkin eine Fachlichkeit. Innerhalb des Features schreibt man die Testfälle, sogenannte Scenarios. Einen Testfall mit mehreren Ausprägungen schreibt man in Gherkin in Scenario Outlines.

In einem Testfall (Scenario) folgen die Testschritte. Diese orientieren sich an BDD und werden mit Hilfe von Given, When, Then und zusätzlich And und But geschrieben.

Gherkin bietet auch die Möglichkeit, Tags zu verwenden. Mit Hilfe dieser kann ich beispielsweise Feature-Toggle-Zustände abbilden oder Testfälle filtern. Die Filterung ist für die TDD-/Test-First-Methode hilfreich.

Nachfolgende Beispiele sollen die Gherkin-Syntax noch einmal veranschaulichen. Das Feature beschreibt eine Fachlichkeit, welche beschrieben wird und im Feature File getestet werden soll.

Feature: Bots werden im Clickstream geflaggt [STORY]
Wir erkennen Bots anhand statischer Listen von IPs, User-Agents und      
Kombinationen aus IP und User-Agent.
Confluence-Info: [LINK]
Scenario: 1 Wird ein Request anhand des UserAgent als Bot identifiziert, wird dieser Request mit dem Label ot_Bot markiert.

  Given Besucher startet auf der Storefront mit als Bot identifizierten User-Agent
  Then  ECS enthält Bot-Informationen
    | Key    | value     |
    | ot_Bot | userAgent |

Nach der Beschreibung der Fachlichkeit folgen die Testfälle. Ein Scenario beschreibt und testet einen Testfall. Innerhalb dieses formuliert man die Testschritte aus der von BDD bekannten Syntax (Given, When, Then).

Hier das komplette Feature mit seinen Testfällen in der Gherkin-Syntax:

Feature: Bots werden im Clickstream geflaggt [STORY]
Wir erkennen Bots anhand statischer Listen von IPs, User-Agents und Kombinationen aus IP und User-Agent.
Confluence-Info: [LINK]

  Scenario: 1 Wird ein Request anhand des UserAgent als Bot identifiziert, wird dieser Request mit dem Label ot_Bot markiert.

    Given Besucher startet auf der Storefront mit als Bot identifizierten User-Agent
    Then  ECS enthält Bot-Informationen
      | Key    | value     |
      | ot_Bot | userAgent |

  Scenario: 2 Wird ein Request anhand der IP-Adresse als Bot identifiziert, wird dieser Request mit dem Label ot_Bot markiert.

    Given Besucher startet auf der Storefront mit als Bot identifizierten IP-Adresse
    Then  ECS enthält Bot-Informationen
      | Key    | value |
      | ot_Bot | ip    |
@Ignore
Scenario: 1 Wird ein Request anhand des UserAgent als Bot identifiziert, wird dieser Request mit dem Label ot_Bot markiert.

    Given Besucher startet auf der Storefront mit als Bot identifizierten User-Agent
    Then  ECS enthält Bot-Informationen
       | Key    | value     |
       | ot_Bot | userAgent |

@DisabledFeature: STORY-123
Scenario: 2 Wird ein Request anhand der IP-Adresse als Bot identifiziert, wird dieser Request mit dem Label ot_Bot markiert.

    Given Besucher startet auf der Storefront mit als Bot identifizierten IP-Adresse
    Then  ECS enthält Bot-Informationen
       | Key    | value |
       | ot_Bot | ip    |

Dieses Beispiel zeigt die Nutzung von Tags innerhalb eines Feature Files. Mit dem Ignore-Tag (@Ignore) kann man einen Testfall aus der Testausführung ausschließen. Dies ist beispielsweise sinnvoll, um eine CI/CD-Pipeline nicht zu stoppen. Wenn man nach TDD (Test First) arbeitet, dann sind die Testfälle bereits geschrieben, aber noch nicht alle erfolgreich. Somit kann man diese erst einmal für die Testausführung filtern.

Mit dem zweiten Tag kann man den Zustand von Feature Toggles auch in den Cucumber Tests abbilden. Das Scenario 2 aus diesem Beispiel wird also nur ausgeführt, wenn auch der Toggle STORY-123 aktiviert ist.

Feature: Performance Marketing Suchmaschinenerkennung
  Bei Marketing-Einsprüngen (sofern in der Top Level Domain Whitelist bekannt) wird sowohl das Suchwort als auch die Suchmaschine getrackt.
  Hier extrahieren wir die SearchEngine anhand des http-Referrers.
  Confluence-info: [LINK]

  Scenario Outline: 1 Suchmaschinenerkennung

    Given Besucher startet auf einer externen Artikeldetailseite mit gesetztem Referrer <url>
    Then  ECS enthält auf oberster Ebene mindestens:
      | key                    | value            |
      | pm_OriginSearchKeyword | <search_keyword> |
      | pm_SearchEngine        | <searchengine>   |

    Examples:
      | url                                       | search_keyword | searchengine                |
      | www.1und1.de           | suchwort       | www.1und1.de         |
      | www.about.com          | suchwort       | www.about.com        |
      | suche.aol.de           | suchwort       | suche.aol.de         |
      | www.ask.de             | suchwort       | www.ask.de           |
      | www.avira.net          | suchwort       | www.avira.net        |
      | www.baidu.de        | suchwort       | www.baidu.de         |
      | www.bing.de            | suchwort       | www.bing.de          |
      | www.blekko.com         | suchwort       | www.blekko.com       |
      | www.claro-search.com   | suchwort       | www.claro-search.com |
      | www.conduit.com        | suchwort       | www.conduit.com      |

Dieser Code zeigt einen Auszug aus einem Scenario Outline. Dies ermöglicht die Abbildung von verschiedenen Ausprägungen in einem Testfall. Die Abbildung der Ausprägungen in einem Scenario (Testfall) erspart es, diesen Testfall mehrfach schreiben oder kopieren zu müssen, um eine weitere Ausprägung zu testen. Bei der Testausführung werden alle Ausprägungen in einem Testfall durchlaufen.

Die Ausprägungen sind in der Examples-Tabelle definiert und werden an entsprechender Stelle im Testfall genutzt. Beispielsweise wird die URL im Testschritt Given (Vorbedingung) eingesetzt.

Dieses Beispiel zeigt nun die Integration und Nutzung des Cucumber-und Gherkin-Plugins in einer IDE, in diesem Fall IntelliJ. Es ermöglicht eine bessere Lesbarkeit durch eine ansehnliche Formatierung und bietet zudem eine Autovervollständigung bei der Formulierung meiner Testschritte, welche sehr hilfreich ist.

Cucumber in der Praxis: Optimierungen durch Teamarbeit und BDD

Nun möchte ich aufzeigen, wie wir Cucumber in unseren Entwicklungsprozess integrierten und somit mehrere Optimierungen in unsere Arbeit bringen konnten.

Eine Anforderung, welche bei uns im Team bearbeitet wird, wird als Story in Jira erstellt und dokumentiert. In der Konzeption und damit der Ausarbeitung der Story (Anforderung) werden die Cucumber-Testfälle geschrieben. Diese Testfälle werden im Projekt, also im Code in der Gherkin-Syntax nach Behavior Driven Development (BDD) formuliert. Dies geschieht durch unsere fachlich verantwortliche:n Business Designer:in (vergleichbar mit Product Owner:in). Unsere BD (Business Designerin) tut dies gemeinsam mit einer:m Entwickler:in oder mit mir als QSler. Wir haben damit gleichzeitig Test Driven Development (TDD) implementiert. Diese Testfälle sind aktuell noch nicht erfolgreich lauffähig.

Es folgt also mit dem Beginn der Entwicklungsphase der Story die funktionale Implementierung im Code und somit das nach und nach erfolgreiche Durchlaufen der Testfälle. Die programmatische Implementierung geschieht durch unsere Entwickler:innen und zum Teil im Sparring oder Pairing mit mir. Ansonsten aber meist im Pair Programming.

Mit Ende der Entwicklungsphase sind die Testfälle dann alle erfolgreich und das Refactoring im Code findet statt. Wie in den vorangegangenen Beispielen ersichtlich, beschreiben wir unsere Fachlichkeiten (Features) und Testfälle (Scenarios). Diese Beschreibungen reichern wir mit einem Hinweis zur Anforderung und weiterführenden Links an.

Entwicklung auf den diesjährigen IT-Tagen

Spannende Vorträge und Workshops zum Thema Entwicklung erwarten Euch auch auf den IT-Tagen, der Jahreskonferenz von Informatik Aktuell. Die IT-Konferenz findet jedes Jahr im Dezember in Frankfurt statt – dieses Jahr vom 08.-11.12.

Fazit

Zusammenfassend haben wir durch die Nutzung von Cucumber als Werkzeug mehrere Dinge erreicht.

  1. Wir integrieren Behavior Driven Development. Dies verbessert unser gemeinsames Verständnis für eine Fachlichkeit oder Anforderung, da wir eine gemeinsame Sprache (Syntax) nutzen.
  2. Wir integrieren Test Driven Development, weil wir die Testfälle bereits mit Anforderungserstellung (Story) schreiben.
  3. Unsere Kollaboration wurde optimiert, da wir neben der einheitlichen Kommunikation auch in den verschiedenen Phasen einer Anforderung gemeinsam arbeiten.
  4. Durch das Werkzeug haben wir eine gemeinsame fachliche Dokumentation an zentraler Stelle, welche für alle verständlich ist und zusätzlich weitere Informationen anbietet.
  5. Wir haben automatisierte Integrationstests zusätzlich zu unseren Unit-Tests.

Autor
Das könnte Sie auch interessieren
Kommentare (0)

Neuen Kommentar schreiben