Overview
In this tutorial, we will create some tests in Cucumber using Java.
Cucumber is mainly a collaboration framework used in BDD context in order to improve shared understanding within the team, usually during "3 Amigos" sessions. That's its main fit.
However, some teams use it in other contexts (e.g. after sofware has being built) for implementing automated tests and take advantage of Gherkin syntax to have visibility/abstraction of the underlying automation code and have reusable automation code.
(Test) Scenarios derived from Cucumber are executable specifications; their statements will have a corresponding code implementation. These test scenarios are feature and more business oriented; they're not unit/integration tests.
Your specification is made using Gherkin (i.e. Given, When, That) statements in Scenario(s) or Scenario Outline(s), eventually complemented with a Background. Implementation of each Gherkin statement (i.e. "step") is done in code; the Cucumber framework finds the code based on regular or cucumber expressions.
Usage scenarios
Cucumber is used in diverse scenarios. Next you may find some usage patterns, even though Cucumber usage is mostly recommended only if you are adopting BDD.
- Teams adopting BDD, start by defining a user story and clarify it using Cucumber Scenario(s); usualy, Cucumber Scenario(s)/Scenario Outline(s) are specified directly in Jira, using Xray
- Teams adopting BDD but that favour a more Git based approach (e.g. GitOps). In this case, stories would be defined in Jira but Cucumber .feature files would be specified using some IDE and would be stored in Git, for example
- Teams not adopting BDD but still using Cucumber, more as an automation framework. Sometimes focused on regression testing; sometimes, for non-regression testing. In this case, cucumber would be used...
- With a user story or some sort of "requirement" described in Jira
- Without any story/"requirement" described in Jira
You may be adopting, or aiming to, one of the previous patterns.
Before moving into the actual implementation, we need to decide which workflow we'll use: do we want to use Xray/Jira as the master for writing the declarative specification (i.e. the Gherkin based Scenarios), or do we want to manage those outside using some editor and store them in Git, for example?
Learn more
Please see Testing in BDD with Gherkin based frameworks (e.g. Cucumber) for an overview of the possible workflows.
The place that you'll use to edit the Cucumber Scenarios will affect your workflow. There are teams that prefer to edit Cucumber Scenarios in Jira using Xray, while there others that prefer to edit them by writing the .feature files by hand using some IDE.
Example
For the purpose of this tutorial, we'll use a simple, dummy Calculator implemented in a Java class as our target for testing.
This tutorial, has the following requirements:
- Java
- Add the dependency of cucumber-jvm (i.e. cucumber-java) to your maven "pom.xml" file
Using Jira and Xray as master
This section assumes using Xray as master, i.e. the place that you'll be using to edit the specifications (e.g. the scenarios that are part of .feature files).
The overall flow would be something like this, assuming Git as the source code versioning system:
- define the story (skip if you already have it)
- create Scenario/Scenario Outline as a Test in Jira; usually, it would be linked to an existing "requirement"/Story (i.e. created from the respective issue screen)
- implement the code related to Gherkin statements/steps and store it in Git, for example. To start, and during development, you may need to generate/export the .feature file to your local environment
- commit previous code to Git
- checkout the code from Git
- generate .feature files based on the specification made in Jira
- run the tests in the CI
- obtain the report in Cucumber JSON format
- import the results back to Jira
Note that steps (5-9) performed by the CI tool are all automated, obviously.
To generate .feature file(s) based on Scenarios defined in Jira (i.e. Cucumber Tests and Preconditions), we can do it directly from Jira, by the REST API or using a CI tool; we'll see that ahead in more detail.
Example
All starts with a user story or some sort of “requirement” that you wish to validate. This is materialized as a Jira issue and identified by the corresponding issue key (e.g. CALC-7931).
We can promptly check that it is “UNCOVERED” (i.e. that it has no tests covering it, no matter their type/approach).
In this case, we'll create a Cucumber Test, of Cucumber Type "Scenario".
We can fill out the Gherkin statements immediately on the Jira issue create dialog or we can create the Test issue first and fill out the details on the next screen, from within the Test issue. In the latter case, we can take advantage of the built-in Gherkin editor which provides auto-complete of Gherkin steps.
After the Test is created, and since we have done it from the user story screen, it will impact the coverage of related "requirement"/story.
The coverage and the test results can be tracked in the "requirement" side (e.g. user story). In this case, you may see that coverage changed from being UNCOVERED to NOTRUN (i.e. covered and with at least one test not run).
Additional tests could be created, eventually linked to the same Story or linked to another one (e.g. multiplication).
The related statement's code is managed outside of Jira and stored in Git, for example.
The tests related code is stored under src/test
directory, which itself contains several other directories. In this case, they're organized as follows:
java/calculator
: step implementation files and test runner class.- The steps "glue-code" is defined in the StepDefinitions class.
You can then export the specification of the test to a Cucumber .feature file via the REST API, or the Export to Cucumber UI action from within the Test/Test Execution issue or even based on an existing saved filter. As source, you can identify Test, Test Set, Test Execution, Test Plan or "requirement" issues. A plugin for your CI tool of choice can be used to ease this task.
So, you can either:
- use one of the available CI/CD plugins (e.g. see details of Integration with Jenkins)
- use the REST API directly (more info here)
#!/bin/bash rm -f features/*.feature curl -u admin:admin "http://jiraserver.example.com/rest/raven/1.0/export/test?keys=CALC-7931;CALC-7935&fz=true" -o features.zip unzip -o features.zip -d features
- ... or even use the UI (e.g. from a Test issue)
We will export the features to a new directory named features/
on the root folder of your Java project (we'll need to tell Maven to use this folder).
After being exported, the created .feature(s) will contain references to the Test issue key, eventually prefixed (e.g. "TEST_") depending on an Xray global setting, and the covered "requirement" issue key, if that's the case. The naming of these files is detailed in Export Cucumber Features.
To run the tests and produce a Cucumber JSON report, we can run Maven and specify that we want a report in Cucumber JSON format and that it should process .features from the features/
directory.
mvn compile test -Dcucumber.plugin="json:report.json" -Dcucumber.features="features/"
This will produce one Cucumber JSON report with all results.
After running the tests, results can be imported to Xray via the REST API, or the Import Execution Results action within an existing Test Execution, or by using one of the available CI/CD plugins (e.g. see an example of Integration with Jenkins).
Which Cucumber endpoint to use?
To import results, you can use two different endpoints/"formats" (endpoints described in Import Execution Results - REST):
- the "standard cucumber" endpoint
- the "multipart cucumber" endpoint
The standard cucumber endpoint (i.e. /import/execution/cucumber) is simpler but more restrictive: you cannot specify values for custom fields on the Test Execution that will be created. This endpoint creates new Test Execution issues unless the Feature contains a tag having an issue key of an existing Test Execution.
The multipart cucumber endpoint will allow you to customize fields (e.g. Fix Version, Test Plan), if you wish to do so, on the Test Execution that will be created. Note that this endpoint always creates new Test Executions (as of Xray v4.2).
In sum, if you want to customize the Fix Version, Test Plan and/or Test Environment of the Test Execution issue that will be created, you'll have to use the "multipart cucumber" endpoint.
A new Test Execution will be created (unless you originally exported the Scenarios/Scenario Outlines from a Test Execution).
One of the tests fails (on purpose).
The execution screen details of the Test Run will provide overall status information and Gherkin statement-level results, therefore we can use it to analyze the failing test.
Results, including for each example on Scenario Outline, can be expanded to see all Gherkin statements.
Note: in this case, the bug was added on purpose on the Calculator class.
Screenshots and other attachments
If available, it is possible to see also attached screenshot(s). For this, you'll need to use Cucumber's API and do it in a After hook, for example (using scenario.embed()).
The icon
represents the evidences ("embeddings") for each Hook, Background and Steps.Results are reflected on the covered items (e.g. Story issues) and can be seen in ther issue screen.
Coverage now shows that the addition related user story (e.g. CALC-7931) is OK based on the latest testing results; on the other hand, the multiplication related user story (CALC-7935) is NOK since it has one test currently failing.
If we fix the code on the Calculator class, run the tests and import results, coverage for the multiplication related user story will be shown as OK.
References
- Sample project cucumber-java-skeleton
- Official Cucumber documentation
- Cucumber installation instructions for Java
- Cucumber API
- Cucumber expressions
- Testing in BDD with Gherkin based frameworks (e.g. Cucumber)
- Automated Tests (Import/Export)
- Exporting Cucumber Tests - REST