In the previous chapter, we saw how to turn our specifications, written in Gherkin, into executable code using Reqnroll. In this chapter, we are going to make our step definitions more versatile by looking at step parameterization, and by using the power of regular expressions to our advantage.
As you convert your examples gathered in the Discovery phase to Gherkin, you might notice that a lot of the steps in your specifications are very similar, and the only thing that varies is a value you send as input to the system you're describing, or observe as output from that system.
As an example, consider the steps 'When they apply for a 999 dollar loan' and 'When they apply for a 1 dollar loan' described in the first Scenario Outline in our specifications here.
It would be very inefficient to create two separate step definitions for these steps, when the only thing that changes is the loan amount, which is a value we likely want to use as input in the acceptance tests for our loan application implementation anyway, for example to fill that value into a form on the UI, or send it as a request body value in an API call. Chances are high that the implementation for both these steps would be exactly the same, no matter the value of the loan amount. This would lead to a lot of duplication in our test code.
This is exactly the reason why Reqnroll, just like pretty much every other tool that supports BDD and Gherkin, allows you to create parameterized steps instead. If you look at the step definitions that have been created, Reqnroll has even identified a potential opportunity for parameterization already, by turning the loan amount into a parameter all by itself. We might want to change the name from p0 to loanAmount, though, to make our code a little more descriptive.
Once we start implementing the step definitions methods, we can refer to the value written in the step using the corresponding argument that is passed to the step definition method. And when the scenario that contains this parameterized step is run, Reqnroll will extract the parameter value from the step and pass it to the body of the step definition method, so it can be used in the acceptance test, either as an input value or an expected output value.
Especially with Scenario Outlines, where the same scenario is repeated multiple times for different examples, you'll probably make good use of parameterized steps.
As you can see, Reqnroll allows us to use a special notation, called Cucumber Expressions, here to denote the variable parts of the step description. These Cucumber Expressions allow you to use parameters in your steps and step definitions using readable keywords, like this. Cucumber Expressions exist for a range of data types, including integers, strings, bytes, and more.
While they're easy to use, sometimes, Cucumber Expressions are not powerful or flexible enough for your needs. This is where regular expressions come in very useful.
Consider the steps containing the expected result of the loan application. In our system, that result will be either approved or it will be denied, and it's likely that these two step definitions will contain the same code: observe the actual loan application result and compare it with the predefined expected result.
So why not limit the options for the value of the expected result to the possible values that can be produced by the loan processor? We can do this easily using this regular expression. This expression only matches the exact values listed in the expression, and nothing else, so this will match approved as well as denied, but no other value. For example, when we use 'processing' as an expected result, Reqnroll tells us there's no matching step definition.
By the way, I wouldn't use this technique once you've got more than, say, 5 possible values in your list, because that will probably make your code harder to read and understand. In those cases, you might want to use some other way of verifying that the value used is a valid one, for example by accepting any string or integer value and dealing with the validation in your step definition implementation code.
So, what to use, Cucumber Expressions or regular expressions? The answer, of course, is 'it depends'. For many people and in many cases, Cucumber Expressions will be enough, and as they're easier to read and to write than regular expressions, they are often a good choice. In some cases, such as the one we saw just earlier, we need the additional matching power provided by regular expressions.
The good news is that you can use a regular expression in one step definition and a Cucumber expression in another without problems in Reqnroll, so you can decide what works best for you for each step definition.
There are many more examples of both regular expressions and Cucumber expressions that can be given. Especially with regular expressions, the opportunities are endless. At the end of the day, though, it is all about making your steps and step definitions more flexible and removing unnecessary duplication in your step definition code.
In the next chapter, we are going to take a look at another technique you can use to make your steps and step definitions more flexible, and that's by using table arguments in your steps and processing them effectively in your step definitions.
The current state of this project is available on GitHub, in the 'chapter6' branch of the repository you see linked in the video right now.