Cucumber und JUnit 5 sind beides beliebte Testing-Frameworks in der Java-Welt. Die Integration beider war aufgrund der unterschiedlichen Konzepte in der Vergangenheit schwierig. Inzwischen unterstützt die neu entwickelte cucumber-junit-platform-engine das Ausführen von Cucumber-Szenarien mittels JUnit 5 fast out-of-the-box. In diesem Artikel zeigen wir, wie Cucumber mit JUnit 5 ausgeführt werden kann und verwenden dafür Gradle in der Kotlin-Notation.

Cucumber

In sogenannten Feature-Files wird die Funktionalität eines Systems beschrieben. Die dabei verwendeten Wörter und Sätze sollten in einer typischen Diskussion innerhalb des Teams vorkommen, wenn das entsprechende Feature besprochen wird. Testszenarien sehen ungefähr wie folgt aus:

Feature: Guess the word

    Scenario: Maker starts a game
        Given the game is setup
        When the Maker starts a game
        Then the Maker waits for a Breaker to join

Jedes Szenario wird durch eine Reihe an Schritten beschrieben, die mit Keywords wie Given, When und Then beginnen. Um diese Schritte auszuführen, muss sogenannter Glue-Code geschrieben werden:

package your.own.steps;

import io.cucumber.java.en.When;
import io.cucumber.java.en.Then;

public class YourSteps {

    @Given("the game is setup")
    public void setup() {
        // execute step
    }

    @When("the Maker starts a game")
    public void someStep() {
        // execute step
    }

    @Then("the Maker waits for a Breaker to join")
    public void otherStep() {
        // execute other step
    }

}

Damit Testszenarien ausgeführt werden können, müssen sowohl Feature-Files also auch der Glue-Code gefunden werden. Um mehr über Cucumber zu erfahren, schaut in den folgenden Post.

JUnit 5

Einer der größten Stärken von JUnit 5 im Vergleich zu seinem Vorgänger ist die Erweiterbarkeit. Das Cucumber-Team bedient sich dieser Erweiterbarkeit mittels der eingangs erwähnten platform-engine, um zusammen mit der junit-platform-suite sowohl Testszenarien als auch Glue-Code zu finden, und anschließend die Testausführung an JUnit zu delegieren. Neben zusätzlichen Abhängigkeiten muss nur noch eine Klasse mit @Suite annotiert und z.B. mit @SelectClasspathResource die oben erwähnten .feature Dateien lokalisiert werden, um die Integration abzuschließen.

package your.own;

import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;

@Suite
@SelectClasspathResource("features")
public class RunCucumberTest {
}

Gradle

Wir benutzen Gradle, um alle notwendigen Abhängigkeiten zu deklarieren und die Testausführung zu konfigurieren. Das folgende Beispiel zeigt ein minimales Setup in Kotlin-Notation, für ein Projekt welches ausschließlich Cucumber-Szenarien beinhaltet und diese ausführen möchte.

plugins {
    java
}

dependencies {
    testImplementation("io.cucumber:cucumber-java:latest.release") {
        because("we want to use Cucumber JVM")
    }
    testImplementation("io.cucumber:cucumber-junit-platform-engine:latest.release") {
        because("we want to use Cucumber with JUnit 5")
    }
    testImplementation("org.junit.platform:junit-platform-suite:latest.release") {
        because("we want to use the JUnit 5 @Suite annotation to select/run Cucumber tests")
    }
    testImplementation("org.junit.jupiter:junit-jupiter-api:latest.release") {
        because("we want to use JUnit 5 assertions")
    }
}

tasks {
    test {
        systemProperties(project.gradle.startParameter.systemPropertiesArgs)
        useJUnitPlatform {
            excludeTags("disabled")
            includeTags("!ignore")
        }
    }
}

Einmal eingerichtet, reicht ein einfaches gradle test aus, um alle Szenarien auszuführen. Wie im Codebeispiel im unteren Abschnitt zu sehen ist, können Properties an Tests übergeben werden, um z. B. die parallele Ausführung von Szenarien zu erlauben oder um bestimmte Szenarien zu ignorieren.

Für Leute mit Zeitdruck haben wir unter https://github.com/cronn/cucumber-junit5-example ein Beispiel hochgeladen.