# Upgrading to JUnit 5 with Cucumber 7: Reasons to Consider

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`](http://junit-platform.properties).

To control properties such as the desired parallelism and maximum parallelism, Cucumber supports JUnit 5s `ParallelExecutionConfigurationStrategy`. [More on this here.](https://www.bookstack.cn/read/junit-5-en/spilt.19.spilt.2.7e376fa28910e03c.md)

## 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.

```graphql
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:

```diff
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.

```graphql
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:

```graphql
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 `DiscoverySelector`s 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](https://junit.org/junit5/docs/current/user-guide/#launcher-api-discovery).

### 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`.

```graphql
@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`.

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

[Explore more here](https://junit.org/junit5/docs/current/user-guide/#running-tests-tag-expressions)

---

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.

%[https://www.buymeacoffee.com/skyboundlife]
