There is no point in repeating on how to use Cucumber and write test cases that is written elsewhere. So here is just a list of links which were (most) helpful when starting on the Cucumber journey. Please extend.
-
Main Website
-
Writing Feature Files
-
with JUnit 5
-
Spring Injection with Cucumber
Cucumber can be run as a stand-alone application as well as integrated with JUnit. We have chosen the latter to make things simpler from the CI/CLI perspective, ie. all tests are executed via mvn test/verify. This means and has the advantage that the Cucumber tests are always run alongside the normal JUnit-based tests.
The only drawback of this is, that all Cucumber tests are spawned by one JUnit tests, which in turn means that it must run all Cucumber from start to end, independent of their respective outcome. I have not found an obvious way to make the CucumberIT fail after completion with JUnit means. This is now down thru the maven plugin https://github.com/damianszczepanik/maven-cucumber-reporting with checkBuildResult=true. This plugin is executed in the verify phase and hence mvn verify
needs to be used to make use of that.
Implementing Cucumber Tests (technical part)
The basic integration of Cucumber with JUnit 5 and Spring is fairly straight forward (once I sifted through all the older guides for JUnit 4):
<!-- #### cucumber related things under -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit-platform-engine</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>junit</artifactId>
<groupId>junit</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-spring</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<build>
<testResources>
<testResource>
<directory>${project.basedir}/src/test/resources</directory>
</testResource>
<!-- i want my resources next to my test classes, also needed for cucumber -->
<testResource>
<directory>${project.basedir}/src/test/java</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</testResource>
</testResources>
<plugins>
<plugin>
<!-- https://github.com/damianszczepanik/maven-cucumber-reporting-->
<groupId>net.masterthought</groupId>
<artifactId>maven-cucumber-reporting</artifactId>
<version>${maven-cucumber-reporting-version}</version>
<executions>
<execution>
<id>execution</id>
<phase>verify</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<!-- <projectName>cucumber-jvm-example</projectName>-->
<!-- optional, per documentation set this to "true" to bypass generation of Cucumber Reports entirely, defaults to false if not specified -->
<skip>false</skip>
<!-- optional, defaults to outputDirectory if not specified -->
<inputDirectory>${project.build.directory}/cucumber-report</inputDirectory>
<!-- output directory for the generated report -->
<outputDirectory>${project.build.directory}/cucumber-report</outputDirectory>
<jsonFiles>
<param>**/*.json</param>
</jsonFiles>
<!-- optional, defaults to outputDirectory if not specified -->
<!-- <classificationDirectory>${project.build.directory}/classifications</classificationDirectory>-->
<!-- <classificationFiles>-->
<!-- <!– supports wildcard or name pattern –>-->
<!-- <param>sample.properties</param>-->
<!-- <param>other.properties</param>-->
<!-- </classificationFiles>-->
<parallelTesting>false</parallelTesting>
<!-- optional, set true to group features by its Ids -->
<mergeFeaturesById>false</mergeFeaturesById>
<!-- optional, set true to get a final report with latest results of the same test from different test runs -->
<mergeFeaturesWithRetest>false</mergeFeaturesWithRetest>
<!-- optional, set true to fail build on test failures -->
<checkBuildResult>true</checkBuildResult>
</configuration>
</execution>
</executions>
</plugin>
src/test/resources/junit-platform.properties
cucumber.plugin=pretty,json:target/cucumber-report/cucumber.json
cucumber.publish.enabled=false
cucumber.publish.quiet=true
cucumber.filter.tags=not @Disabled
This servers as the entry point for JUnit to start the Cucumber tests, which is all done via the annotations.
If the the .feature and classes implementing the steps are created is in the same package as the CucumberIT class (or below?), then these files are auto-discovered and all works out-of-the box.
@SpringBootTests //customize this this with our specific Spring test context/annotations if needed
@CucumberContextConfiguration
@Cucumber
public class CucumberIT {
}
This contains the test scenarios/cases to be written in Gherkin.
These are normal Java Classes and conceptually correspond to JUnit Test Classes
JUnit | Cucumber | Comment |
---|---|---|
Test Case |
Scenario |
|
Parameterized Tests |
Scenario Template/Outline |
|
Test Class |
Step Definition Class |
1 instance per executed test method → member vars can hold state between steps |
@Before/AfterEach Test Case |
@Before/After Scenario |
|
@Befor/AfterAll |
n/a |
|
n/a |
@BeforeStep/AfterStep |
not sure what good use case this can be used for except logging or such. |