Another year, another major version.
Below we'll discuss some notable changes in v7.0.0 As always the full change log can be found in the usual place.
Prior to v11 Cucumber Expressions were transformed into regular expressions using a string substitution algorithm. This algorithm had a number of edge cases.
Starting with v11 the Cucumber Expressions are described by their own grammar. This fixes various ambiguities and bugs in the way Cucumber expressions are parsed and transformed into regular expressions. This may however also break Cucumber Expressions that depend on these ambiguities.
The Cucumber-Java module now supports before-all and after-all hooks. This closes one of the longest-open issues our issue tracker.
The hooks have 'invoke around' semantics. All before-hooks will be executed before any scenario is executed. After all scenarios have been executed all after-hooks will be executed.
package io.cucumber.example;
import io.cucumber.java.AfterAll;
import io.cucumber.java.BeforeAll;
public class StepDefinitions {
@BeforeAll
public static void beforeAll() {
// Runs before all scenarios
}
@AfterAll
public static void afterAll() {
// Runs after all scenarios
}
}
The CucumberJUnit Platform Engine has been updated to 1.8. With JUnit 5.8 comes
the junit-platform-suite
engine. This engine allows the
programmatic declaration of test suites.
So it is now possible to write the following JUnit 4 test:
package com.example;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;
@RunWith(Cucumber.class)
@CucumberOptions(glue = "com.example.application", features = "classpath:com/example/application")
public class RunCucumberTest {
}
As a declarative JUnit 5 test suite:
package com.example;
import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;
import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;
@Suite
@IncludeEngines("cucumber")
@SelectPackages("com.example.application")
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example.application")
public class RunCucumberTest {
}
In combination with the before-all and after-all hooks this allows for a feature-complete migration from JUnit 4.
Unfortunately Gradle and Surefire still only provide limited support for file
based tests. While Cucumber tests can be executed, the results are reported in
a <Class Name> - <Method Name>
format. As a result only scenario names or
example numbers are reported. This can make for hard to read reports.
By using cucumber.junit-platform.naming-strategy=long
Cucumber will include
the feature name in the scenario name. This makes the test results legible.
e.g for Maven:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<properties>
<configurationParameters>
cucumber.junit-platform.naming-strategy=long
</configurationParameters>
</properties>
</configuration>
</plugin>
or for Gradle:
tasks.test {
useJUnitPlatform()
systemProperty("cucumber.junit-platform.naming-strategy", "long")
}
Finally, the @Cucumber
annotation has been deprecated in favour of @Suite
.
The @Cucumber
annotated class was originally intended as a workaround for
both JUnit 5's lack of suites and Gralde and Surefires inability to discover
non-class based. The with the introduction of the junit-platform-suite
the
@Suite
annotation can do both.
It's a Bill of Materials (BOM) to help keep all dependencies aligned.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-bom</artifactId>
<version>${cucumber.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!--Then for example-->
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit-platform-engine</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
The AbstractTestNGCucumberTests
will now pick up properties from testng.xml
.
This allows the same runner to be reused in multiple suites. For example:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Example Suite">
<parameter name="cucumber.filter.tags" value="@Gherkin and not @Zucchini" />
<test name="Vegetable garden" preserve-order="true">
<parameter name="cucumber.features" value="classpath:com/example/features/vegetable"/>
<parameter name="cucumber.glue" value="com.example.vegetables.glue"/>
<classes>
<class name="com.example.RunCucumberTests"/>
</classes>
</test>
<test name="Herb garden" preserve-order="true">
<parameter name="cucumber.features" value="classpath:com/example/features/herbs"/>
<parameter name="cucumber.glue" value="com.example.herbs.glue"/>
<classes>
<class name="com.example.RunCucumberTests"/>
</classes>
</test>
</suite>
Datatables can be transformed into lists, maps, lists of maps and other objects
using the DataTable.asX
methods. However not all asX
methods would use the
@DataTableType
transformers that had been defined for them.
To avoid confusion all DataTable.asX
methods now use a transformer. There are
however a few cases where a transform should not be used (such as inside an
@DataTableType
annotated method). So to retain the old behaviour:
- Replace
DataTable.asList()
with ->DataTable.values()
- Replace
DataTable.asLists()
with ->DataTable.cells()
- Replace
DataTable.asMaps()
with ->DataTable.entries()
Since v6 Cucumber has been executing scenarios in strict mode by default. This means that pending and undefined steps will always fail the build. This ensures that third party tools do not have to guess if pending and undefined steps should fail a test run.
To make migration graceful the --strict
and --non-strict
CLI arguments and
cucumber.execution.strict
property were left in place. These have now been
removed.
Due to technical difficulties, the cucumber-java8
module is currently
under consideration for removal.
While alternatives are explored,
you can already migrate to cucumber-java
annotation based step definitions automatically.
For now Cucumber-Java8 is removed as recommendation.