Skip to content

Instantly share code, notes, and snippets.

@elonderin
Created September 10, 2021 14:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save elonderin/95f780aad93e6330b9c1edfeba47a0c9 to your computer and use it in GitHub Desktop.
Save elonderin/95f780aad93e6330b9c1edfeba47a0c9 to your computer and use it in GitHub Desktop.
cucumber + junit 5 + spring

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.

Integrate Cucumber in a Maven Project

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):

Step: Add these dependencies to the POM

add to /project/dependencies
        <!--  #### 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>
add this to the appropriate /../build section, e.g. /project/build or /project/profiles/profile[id=?]/build
    <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>

Step: Add Cucumber properties

via 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

Step: Create the JUnit Test Stub

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 {
}

Step: Add a Cucumber .feature file(s)

This contains the test scenarios/cases to be written in Gherkin.

Step: Add implementations in Step-Classes

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment