Upgrading to JUnit 5 with Cucumber 7: Reasons to Consider

Upgrading to JUnit 5 with Cucumber 7: Reasons to Consider

·

4 min read

As a software developer, testing is an essential part of ensuring the quality and reliability of our applications. With the latest versions of JUnit and Cucumber, we now have a powerful combination that takes our testing capabilities to the next level.

In this blog post, we'll explore the benefits of using JUnit 5+ with Cucumber 7+ and how this dynamic duo can supercharge your testing process.

Parallel execution

Cucumber executes tests in a sequential manner by default, utilizing a single thread. However, the option to run tests in parallel is available, but it requires explicit activation.
Due to limitations JUnit 4 could only execute features in parallel. This meant that the Scenarios within a feature file never executed in parallel. This is now possible.

To enable parallel execution, set the cucumber.execution.parallel.enabled configuration parameter to true, e.g. in junit-platform.properties.

To control properties such as the desired parallelism and maximum parallelism, Cucumber supports JUnit 5s ParallelExecutionConfigurationStrategy. More on this here.

Exclusive Resources

To prevent flaky tests when multiple scenarios manipulate the same resource, tests can be synchronized based on that resource.

To synchronize a scenario on a specific resource, the scenario must be tagged, and this tag should be mapped to a lock for that particular resource. A resource is identified by an arbitrary string and can be locked with either a read-write lock or a read lock.

Feature: Exclusive resources

   @reads-and-writes-system-properties
   Scenario: Example one
      Given AUT component reads and writes system properties
      When it is performing operations
      Then it will not be executed concurrently with the second example

   @reads-system-properties
   Scenario: Example two
      Given AUT component reads system properties
      When it is performing operations
      Then it will not be executed concurrently with the first examplegh

with this configuration:

cucumber.execution.exclusive-resources.reads-and-writes-system-properties.read-write=java.lang.System.properties
cucumber.execution.exclusive-resources.reads-system-properties.read=java.lang.System.properties

When running the first scenario tagged with @reads-and-writes-system-properties, it locks the java.lang.System.properties resource with a read-write lock. It won't run at the same time as the second scenario that locks the same resource with a read lock.

Running tests in isolation

To guarantee isolated scenario execution, use the global resource org.junit.platform.engine.support.hierarchical.ExclusiveResource.GLOBAL_KEY to prevent simultaneous runs.

Feature: Isolated scenarios

   @isolated
   Scenario: isolated example
      Given this scenario runs isolated
      When it is executed
      Then it will not be executed concurrently with the second or third example

   Scenario: second example
      When it is executed
      Then it will not be executed concurrently with the isolated example
      And it will be executed concurrently with the third example

   Scenario: third example
      When it is executed
      Then it will not be executed concurrently with the isolated example
      And it will be executed concurrently with the second example

with this configuration:

cucumber.execution.exclusive-resources.isolated.read-write=org.junit.platform.engine.support.hierarchical.ExclusiveResource.GLOBAL_KEY

It is possible that our current feature files contain scenarios that are not independent (which is not recommended). However, when transitioning scripts from JUnit 4 to JUnit 5, we can configure the following property to maintain parallel execution (of JUnit4):
cucumber.execution.execution-mode.feature=same_thread


Supported Discovery Selectors and Filters

JUnit 5 introduced a test discovery mechanism as a dedicated feature within the platform. This allows Integrated Development Environments (IDEs) and build tools to identify tests.

Supported DiscoverySelectors are:

  • ClasspathRootSelector

  • ClasspathResourceSelector

  • ClassSelector

  • PackageSelector

  • FileSelector

  • DirectorySelector

  • UriSelector

  • UniqueIdSelector

The only supported DiscoveryFilter is the PackageNameFilter and only when features are selected from the classpath. More on this here.

Selecting specific scenarios, rules, and examples

The FileSelector and ClasspathResourceSelector support a FilePosition.

  • DiscoverySelectors.selectClasspathResource("rule.feature", FilePosition.from(5))

  • DiscoverySelectors.selectFile("rule.feature", FilePosition.from(5))

The UriSelector supports URIs with a line query parameter:

  • classpath:/com/example/example.feature?line=20

  • file:/path/to/com/example/example.feature?line=20

Any TestDescriptor that matches the line and its descendants will be included in the discovery result. For example, selecting a Rule will execute all scenarios contained within the Rule.

Tags

Cucumber tags are mapped to JUnit tags. It is important to note that the "@" symbol is not included as part of the JUnit tag.
So the scenarios below are tagged with Smoke and Sanity.

@Smoke
@Ignore
Scenario: Example one tagged
  Given I tag a scenario 
  When I select tests with that tag for execution 
  Then my tagged scenario is executed

@Sanity
Scenario: Example two tagged
  Given I tag a scenario 
  When I select tests with that tag for execution 
  Then my tagged scenario is executed

When using Maven, tags can be provided from the CLI using the groups and excludedGroups parameters. These take a JUnit5 Tag Expression. The example below will execute Another tagged scenario.

mvn verify -DexcludedGroups="Ignore" -Dgroups="Smoke | Sanity"

Explore more here


Dear Readers,

I hope you are enjoying the content I provide on my blog. As a passionate writer and dedicated software developer, I strive to create valuable and informative articles that resonate with you. Today, I would like to extend an invitation to support my work and help me continue producing high-quality content.

I have set up a Buy Me a Coffee page, a platform that allows readers like you to show their appreciation by making a small donation. Your contribution, no matter how big or small, goes a long way in supporting my efforts and keeping the blog running. You can also sponsor using the links at the bottom of this page.

Did you find this article valuable?

Support Ish Mishra by becoming a sponsor. Any amount is appreciated!