Introduction
Part of optimizing your Scenarios within your Features is to ensure you have succinct, reusable test steps. This means making your test steps generic enough to encompass all inputs and variations, but also specific enough to only tie to the implementation you desire. A large part of being successful in this task is to have well written Regular Expressions in the your definitions, and making smart Glue Code decisions.
A previous post went over regular expressions, and now it’s time to make use of them.
Glue Code Background
Glue Code is the code that interacts directly with your application. There are two kinds of Glue code – Step Definitions and Hooks. As we already covered hooks in another post, we’ll be focusing on the Step Definitions side of things today.
First off, a few best practices when creating your Step Definitions (or really any Glue Code).
- The matcher is not overly verbose
- The matcher handles both positive and negative (true and false) conditions
- The matcher has at most two value parameters
- The parameter variables are clearly named
- The body is less than fifteen lines of code
- The body does not call other steps
Keep all of these in mind as we discuss setting up the Glue Code.
When we are writing our Step Definitions, there are three main pieces to consider. The regular expression capturing our test step, the method declaration setting up our variables, and the actual method implementation, performing all of the work.
When you put part of a regular expression in parentheses, whatever it matches gets captured for use later. This is known as a ‘capture group.’ In Cucumber, captured strings become step definition parameters. Typically, if you’re using a wildcard, you probably want to capture the matching value for use in your step definition.
Given("^I'm logged in as an? (.*)$") public void ImLoggedInAsA(String role) { //log in as the given role }
If your step is Given I’m logged in as an admin, then the step definition gets passed “admin” for role. Cucumber converts captured strings to the step definition parameter type, which is handy for step definitions like this:
Given("^I have (\\d+) users$") public void howManyUsers(int users) { //do something with our users }
The step Given I have 42 users means the step definition gets called with 42 (as an integer) howManyUsers. Sometimes, you have to use parentheses to get a regular expression to work, but you don’t want to capture the match.
Given("^(I'm logged|I log) in as an? (.*)$") public void ImLoggedInAsA(string role) { //login as the given role }
The parentheses and pipe indicate a logical OR, just what I need to match two different strings.
This will fail to run, though.
My regular expression is capturing two strings, but my step definition method only takes one.
I need to designate the first group as non-capturing like this:
Given("^(?:I'm logged|I log) in as an? (.*)$") public void ImLoggedInAsA(string role) { //login as the given role }
Now, with the addition of ?: at the beginning of the group, it will perform as I expect.
Lists can also be supplied: When I’m available on Monday,Tuesday,Wednesday
When("^I'm available on (.*)$") public void AvailableOn(Listdays) { //check the available days }
7 thoughts to “Exploring Glue Code with Cucumber-JVM”
Thanks Max, that was a great help
Pingback: Making Cucumber Glue Code More Explicit with Transformers - Coveros
Great post. Thanks.
Minor comment: you should escape the d in (d+) as an argument. it should be (\\d+) when using Java.
Thanks for catching that!!
Pingback: Using Dependency Injectors to Simplify Your Code in Cucumber
I need to read scenario name in the glue file. Can we read it into a variable?
How are you looking to use it in the glue code file?
The easiest way to get access to all information about the scenario is by retrieving it in an @Before or @After method. If you need it in the glue code itself, you could consider saving the variable off to a common file, depending on your cucumber framework. I personally like using dependency injection, to pass variables from one glue code class to another, which I would also use for this. It might look something like:
public class Configuration {
protected Controller controller;
public Configuration(Controller controller) {
this.controller = controller;
}
@Before
public void setup(Scenario scenario) {
controller.setScenario(scenario);
}
}
In this case, I would then setup a custom dependency injection to pass my Controller class into each of my glue code files