DRY – one of the many reasons to upgrade to SpecFlow 1.9
Having been using SpecFlow for almost two years, I was very excited about the (long awaited) release of SpecFlow 1.9. It’s packed with so many goodies that I really think it should have been called 2.0. But Gaspar Nagy is a modest man
There is no point of listing here all new SpecFlow features – you can read it here. In this blog I’d like to focus on one particular improvement that made me upgrade my projects immediately. Because it helps against text duplication. Let’s see how.
Original Cucumber approach to variables is to represent them in step definitions using regular expressions, so they can be matched and replaced with instance data. Even hardcore regex lovers should admit that regular expressions don’t really fit in environment where the goal is to present specifications and tests using natural language. So there’s been numerous attempts in various Cucumber ports to provide alternative conventions.
Here are a few step definitions from a project I am working on. You don’t need to pay attention to service names and other domain-specific stuff – this time we’ll look at the ceremony around it, or in fact reducing this ceremony. So let’s look at how the step definitions were written prior release of SpecFlow 1.9.
I have marked SpecFlow binding attributes – they are just Gherkin phrases except for the variables represented by regular expressions. They are attached to method with names that are also (at least when generated by SpecFlow) same Gherkin phrases with underscores replacing spaces (you can keep spaces when writing step definitions in F#) and variables moved to a method parameter list.
So we have three variations of the same Gherkin phrase: first in the original feature file, second in a method name and third in the attached .NET attribute (Given, When or Then). We have to keep two of them in order to bind the feature and the steps, but can we get rid of the third one?
With SpecFlow 1.9 we can – unless we have special reasons to match variables using regular expressions, and in most of the specifications I’ve seen there were no such reasons. The feature text can be mapped directly to the method names if we add a simple convention to represent variables.
We’ll begin by removing text from the Given/When/Then attributes, as you can see below.
If you were systematic about step definitions method names so they matched related Gherkin text and if .NET attribute texts that you removed didn’t contain regular expressions, SpecFlow will be able to bind methods to Gherkin phrases. If method names were different or if step definitions used regular expressions, SpecFlow will display unmatched steps in purple. In our example this will be a method that used regular expression matching return code:
We need to fix unmatched steps. This is as easy as extending a method name with a variable name written in capitalized form and separated with underscores. So if your original Gherkin phrase was “Service should return OK” and you want “OK” to be an instance of a variable, then in a step definition you should declare such variable as you do in standard Cucumber approach, let’s say it’s called “returnCode” and call a method “Service_should_return_RETURNCODE”. This will do the trick.
After saving the step definition file we can check the feature file and verify that the purple color is gone: SpecFlow restored the step binding:
If you are like me and hate typing same text multiple times, you may want to start refactoring your step definitions immediately. Bear in mind however a couple of things to ensure the transition to regex-free step definitions will be smooth:
- Your step definition method names should match Gherkin steps, otherwise SpecFlow won’t be able to bind them. If you accepted SpecFlow automatic method generation and updated method names whenever you changed Gherkin steps, you will be rewarded. But even if you didn’t, there is not much to worry about: as you saw, SpecFlow will kindly display in purple all unmatched steps, so a quick feature definition review will uncover all missing bindings.
- If your variables in your step definitions used special formatting, for example, were enclosed in double-quotes like some of the variables in the example above, you will have to remove special formatting or keep regular expressions. Regex-free approach interprets the whole string as a variable, so spend some time on regression testing after the refactoring. I first didn’t notice double-quotes in my Gherkin steps, and most of the related tests failed. Fortunately, this is usually easy to fix.