An extension to Cucumber for Java based on Cucumber Guice, with scenario variables support, assertion support and some pre-defined utility steps.
It augments your Cucumber based test framework with some powerful features, such as:
<dependency>
<groupId>io.github.fslev</groupId>
<artifactId>cucumber-jutils</artifactId>
<version>${latest.version}</version>
</dependency>
Gradle: compile("io.github.fslev:cucumber-jutils:${latest.version}")
Cucumber-JUtils requires the following dependencies inside your project:
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-guice</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>${guice.version}</version>
</dependency>
In order to integrate cucumber-jutils within your test project you must configure the following glue package inside your IDE Cucumber plugin or / and inside the code:
com.cucumber.utils
Follow the Cucumber JUtils Tutorial for a better picture on how this library should be used.
Scenario variables can be set and read inside Gherkin syntax, Java code and resource files.
These variables are scenario scoped. Meaning, they live as long as the scenario is running and they cannot be accessed from another scenario.
Scenario variables are read using #[
and ]
delimiters.
Important note: If you want to use scenario variables inside your step arguments, your step definition has to use anonymous parameter types.
Variables can be set using different pre-defined steps:
Example:
Scenario: Test scenario variables
* var animal="rabbit"
* var location="forest"
* [util] Match some rabbit with some #[animal]
* [util] Match forest with #[location]
As you can see bellow, the matching step is defined with anonymous parameter types:
@Then("[util] Match {} with {}")
public void match(Object expected, Object actual) {
Defines a variable with value from doc string:
Scenario: Test scenario variable set from doc string
* var animal=
"""
rabbit
"""
* [util] Match some rabbit with some #[animal]
Defines a variable with value from file content:
File: features/readme/vars/madagascar.crt
macac
Scenario: Test scenario variable set from file
* var animal from file "features/readme/vars/madagascar.crt"
* [util] Match macac with #[animal]
Loads the properties from a file, as scenario variables: .properties
, .yaml
, .yml
.
Example:
File: features/readme/vars/config.properties
animal = lioness
location = Africa
Scenario: Test scenario variables set from properties file
* load vars from file "features/readme/vars/config.properties"
* [util] Match lioness with #[animal]
* [util] Match Africa with #[location]
It reads recursively the entire directory tree structure and each file becomes a scenario variable:
file name, without extension -> variable name
file content -> variable value
Supported file types: .txt
, .text
, .json
, .xml
, .html
, .csv
Properties inside files: .properties
, .yaml
, .yml
are also parsed as scenario variables.
Example:
Directory: placeholders/properties/drinks
File: whisky.txt
Johnny Walker
File: drink.yaml
beer: Bergenbier
beers:
-
Ursus
-
Heineken
Scenario: Test scenario variables set from directory
* load vars from dir "placeholders/properties/drinks"
* [util] Match Johnny Walker with #[whisky]
* [util] Match Bergenbier with #[beer]
* [util] Match ["Ursus", "Heineken"] with #[beers]
Defines a variable with value from data table:
Scenario: Test scenario variable set from table
* var animals from table
| feline | marsupial |
| lioness | kangaroo |
| cougar | tasmanian devil |
* [util] Match [{"feline":"lioness", "marsupial":"kangaroo"}, {"feline":"cougar", "marsupial":"tasmanian devil"}] with #[animals]
Scenario variables can also be set and used directly inside Java code, by injecting the ScenarioVars.class
.
Variables defined inside Gherkin files can be used from Java code and vice versa.
Set variables inside a step and use them from another step
public class ScenarioVarsReadmeSteps {
@Inject
private ScenarioVars scenarioVars;
@Given("Some random step which sets some variables")
public void setVariables() {
scenarioVars.put("animal", "Cheetah");
Map<String, Object> vars = new HashMap<>();
vars.put("figure", "triangle");
vars.put("number", 10);
scenarioVars.putAll(vars);
}
}
public class ScenarioVarsAnotherReadmeSteps {
@Inject
private ScenarioVars scenarioVars;
@Given("Some random step which reads the variables")
public void readVariables() {
assertEquals("Cheetah", scenarioVars.getAsString("animal"));
assertEquals("triangle", scenarioVars.getAsString("figure"));
assertEquals(10, scenarioVars.get("number"));
}
}
Set and use variables from both Gherkin and Java:
Scenario: Use scenario variables from Java and Gherkin
* Some random step which sets some variables
* [util] Match Cheetah with #[animal]
* var planet="Mars"
* Some random step which reads variables set inside Gherkin
@Inject
private ScenarioVars scenarioVars;
@Given("Some random step which reads variables set inside Gherkin")
public void readVariablesSetViaGherkin() {
assertEquals("Mars", scenarioVars.getAsString("planet"));
}
Similar to the Gherkin steps, scenario variables can also be set from files:
@Inject
private ScenarioVars scenarioVars;
@Given("Read scenario variables from file")
public void setVariablesFromFile() {
ScenarioVarsUtils.loadScenarioVarsFromFile("features/readme/vars/config.properties", scenarioVars);
ScenarioVarsUtils.loadScenarioVarsFromDir("placeholders/properties/drinks", scenarioVars);
assertEquals("Africa", scenarioVars.get("location"));
assertEquals("Johnny Walker", scenarioVars.get("whisky"));
}
You may parse resource files for scenario variables, delimited by #[
and ]
.
File path: features/readme/scene/some_text.txt
The #[animal] lives in #[location]
Scenario: Parse files for scenario variables
* var animal="wolf"
* var location="forest"
* Parse file for scenario variables
@Inject
private ScenarioVars scenarioVars;
@Given("Parse file for scenario variables")
public void parseFileForScenarioVars() {
assertEquals("The wolf lives in forest", ScenarioVarsUtils.parse("features/readme/scene/some_text.txt", scenarioVars));
}
For JSON type variables you may access certain values by using Jackson paths /
:
* var x=
"""json
{"book":{
"details":{"title":"Moby Dick"}
}
}
"""
* [util] Match #[x/book/details/title] with Moby Dick
Play with the Readme examples for getting a better insight on how scenario variables work.
Cucumber-JUtils already ships with JTest-Utils that has some powerful assertions in terms of Objects matching.
You may use SpEL expressions inside Gherkin or resource files, delimited by #{
and }
:
Feature: SpEL
Scenario: Use SpEL inside Gherkin
* var number="5"
* var isOddNumber="#{ #[number] % 2 != 0 }"
* [util] Match true with #[isOddNumber]
SpEL expressions used inside files:
File path: features/readme/scene/some_text_with_spel.txt
"Is #[number] odd: #{ #[number] % 2 !=0 }"
Scenario: Use SpEL inside files
* var content from file "features/readme/scene/some_text_with_spel.txt"
* var number="5"
* [util] Match "Is 5 odd: true" with #[content]
Note: ScenarioVarsUtils.parse()
not only parses for scenario variables, but also for SpEL expressions:
@Inject
private ScenarioVars scenarioVars;
@Given("Parse file for SpEL")
public void parseFileForSpEL() {
assertEquals("\"Is 5 odd: true\"", ScenarioVarsUtils.parse("features/readme/scene/some_text_with_spel.txt", scenarioVars));
}
Scenario: Parse files for SpEL
* var number="5"
* Parse file for SpEL
Play with the Readme examples for getting a better insight on how SpEL expressions are used.
# throws and AssertionError
* [util] Match true with false
* [time-util] Check period from 2019-02-03 23:58:12+0200 to 2019-02-04 01:59:10+0300 is 1 HOURS using date time pattern yyyy-MM-dd HH:mm:ssZ
* var currentMillis="#[now]"
* [time-util] date var currentDate=from millis #[currentMillis] PLUS 0 YEARS with format pattern=yyyy-MM-dd
* [time-util] date var futureDateYears=from millis #[currentMillis] PLUS 15 YEARS with format pattern=yyyy-MM-dd
* [time-util] Check period from #[currentDate] to #[futureDateYears] is 15 YEARS using date pattern yyyy-MM-dd
* [util] Wait 10.471s
* [util] Wait 2.5m
ScenarioVars
- it stores all scenario variables. Access it via injection:com.google.inject.Inject
ScenarioVarsUtils
- it sets scenario variables and parses files for both scenario variables and SpEL expressionsScenarioVarsParser
- it parses a String for scenario variables and SpEL expressionsScenarioUtils
- fast access to the underlying CucumberScenario.class
and used for writing:
@Inject
private ScenarioUtils scenarioUtils;
@Given("write {}=\"{}\"")
public void writeSomething(String name, Object value) {
scenarioUtils.log("var {} = {}", name, value);
scenarioUtils.log("Scenario: {}", scenarioUtils.getScenario().getName());
}
Follow the Cucumber JUtils Tutorial for a better picture on how this library should be used.