Cucumber and JUnit 5 are widely used testing frameworks. Integration both was cumbersome in the past, however the new cucumber-junit-platform-engine simplifies this a lot. The following post describes how that looks like using Gradle.

Cucumber

Gherkin based feature files describe the functionality of a system in a domain specific language. They should use the same words a team uses to discuss a feature.

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

Each scenario describes a series of steps which start with keywords like Given, When, and Then. In order to execute those steps, you have to write some glue code:

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
	}

}

In order to run test scenarios, both feature files and glue code is necessary.

JUnit 5

One of the biggest strengths of JUnit 5 compared to its predecessor is its extensibility. The Cucumber team used that extensibility in order to create a platform-engine to discover feature files and glue code, as well as delegating test execution to JUnit. All you need is another dependency and an additional class annotated with @Cucumber.

package your.own;

import io.cucumber.junit.platform.engine.Cucumber;

@Cucumber
public class RunCucumberTest {
}

Gradle

We are using Gradle in order to declare all required dependencies and configure how we want to run our tests. The following example shows a minimal example written in Kotlin that is capable of running Cucumber scenarios.

plugins {
  java
}

dependencies {
  testImplementation("org.junit.jupiter:junit-jupiter-api:latest.release") {
	because("we want to use JUnit 5")
  }
  testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:latest.release") {
	because("Cucumber relies on jupiter-engine to resolve tests")
  }
  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("io.cucumber:cucumber-picocontainer:latest.release") {
	because("we want to use dependency injection in our Cucumber tests")
  }
}

tasks {
    test {
        systemProperties(System.getProperties().toMap() as Map<String, Any>)
        systemProperty("cucumber.execution.parallel.enabled", System.getProperty("test.parallel"))
        systemProperty("cucumber.filter.tags", "not @ignore")
        useJUnitPlatform {
            excludeTags("disabled")
        }
    }
}

Once the setup is complete, call gradle test to test your scenarios. The code example shows how to pass properties to your test, e.g. to enable parallel execution or to include/exclude certain scenarios.

In order to get started quickly, take a look at the example repository at https://github.com/cronn-de/cucumber-junit5-example.