Stupid Cucumber Tricks
This living blog post provides valuable tips and tricks to make working with the Cucumber easier.
We have long been fans of Behavior-Driven Development (BDD), specifically leveraging cucumber-jvm for our Java projects. BDD allows your requirements and tests to be the flip side of the same coin. It also generally enables the same test functionality we would achieve with traditional JUnit tests but in far less code. This provides readability, understandability, and maintenance benefits.
However, we've noticed that Cucumber has become less intuitive since moving on from the venerable version 1.2.6. We understand the challenges this may pose, so we've compiled this living blog post to share our tips and tricks for working with these later versions of Cucumber. For this post, we'll be focusing on version 7.18.1.
The following topics are covered in this post:
Supporting Lists of Values in an Example Table Cell
Passing Example Table Rows as an Object
Supporting Lists of Values in an Example Table Cell
Challenge
Including a comma-separated list of values in a single cell of an example table is often helpful. Let’s consider the following example:
Scenario Outline: Applies to certain days of the week
Given a "rule>" on which days to apply policy X
When the rule is applied
Then "<daysOfWeek>" are applicable
Examples:
| rule | daysOfWeek |
| weekdays-only | Mon, Tue, Wed, Thu, Fri |
| weekends-only | Sat, Sun |
Passing daysOfWeek
into the implementation methods of this scenario does not just work out of the box like it did in Cucumber 1.2.6. Also, project documentation on how to get to this work is confusing and incomplete.
Solution
To enable this functionality, you must declare a ParameterType
in your project. It is important to note that you only need one declaration. Key implementation notes include:
Your method name will be used as your variable name in the Step mapping annotation. Alternatively, you can specify a name in the
ParameterType.name
field.Once you add this functionality, you must remove all
[^\"]*
regular expression references in Step annotations within your test classes.You MUST wrap this custom parameter type in double quotes within your step definition (see the “step implementation class” example below).
Example
The following snippets represent how this functionality comes together.
// Definition of a ParameterType that can process the comma-separated
// list of values:
@ParameterType(value = "[^\"]*")
public List<String> listOfStrings(String values) {
return StringUtils.isNotBlank(values) ?
Stream.of(values.split(",", 0)).map(String::trim).collect(Collectors.toList())
: new ArrayList<>();
}
// Step implementation class
@Then("\"{listOfStrings}\" are applicable")
public void are_applicable(List<String> listOfStrings) {
// test implementation
}
Passing Example Table Rows as an Object
Challenge
It is often helpful to be able to pass an entire example table row as an object to your test. Again, this needs to be more apparent from the available project documentation. Let’s consider the following example:
Scenario Outline: Applies to specific days of the week
Given the following pitchers on a baseball team:
| name | position | velocityOver100mph |
| Cease | SP | false |
| Saurez | RP | true |
| Morejon | RP | false |
...
Solution
You must declare a DataTableType
in your project. Once this is completed, the functionality will seamlessly work.
Example
// DataTableType definition for the above scenario table
public class PitcherInfo {
public String name;
public String position;
public Boolean velocityOver100mph;
}
@DataTableType
public PitcherInfo pitcherInfoEntry(Map<String, String> entry) {
PitcherInfo input = new PitcherInfo();
input.name = entry.get("name");
input.position = entry.get("position");
input.velocityOver100mph =
Boolean.valueOf(entry.get("velocityOver100mph"));
return input;
}
// Step definition using the DataTableType
@Given("the following pitchers on a baseball team:")
public void this_test_method(List<PitcherInfo> pitchers) {
// write test logic here
}