I started to write a blog post about how I currently go about writing software and what Behaviour Driven Development (BDD) is to me, I got virtually to the end of the first draft, when it occurred to me that I was describing the use of tooling but had not described what the tools actually were! hence this post.
In addition to Visual Studio I am currently using:
A feature file is almost the same as a user story within the agile context, a feature has a simple text description, and a number of structured scenarios each containing a number of steps that describe the setup execution and expected results in a ubiquitous language of the application, for example
The only words required by SpecFlow in this whole feature are the ones in blue, everything else is up to the user, this allows for very specific business domain language to be used and because of the terseness of the required syntax, there is also support for other languages not only English.
Looking at each of the SpecFlow syntax items in turn.
the title of the feature is an important component of the system, this will directly translate into the class name of the generated test, so feature titles must be unique, the remainder of the feature text (after the carriage return) can be styled like the above example using the Connextra format
In order to [benefit]
As a [stakeholder]
I want to [feature]
or simply as a paragraph or more of description, or any other format the user wants to use, after this narrative comes one or more Scenarios which are the heart of the spec flow system.
There can be one or more scenarios for a given feature, these describe how the user interacts with a specific feature using a structured syntax
Given sets up the context for the scenario
When is the action that will create the result
Then asserts that the results created by the action are correct
The And keyword can be used in conjunction with any of the three scenario steps to extend them in a language friendly fashion.
The next stage of the process is to create the step definitions which link our text feature file to the production code. A step definition is simply a class with the binding attribute and a method with the given, when or then attribute attached. The method attribute is the binding that links the method to a step in a feature file.
I actually copied these definitions from the NUnit text output window, when the specifications are run without definitions, the test runner outputs example steps for the developer to copy. Notice how the “And” has now become a “Given”, the ‘And’ keyword becomes the parent ‘Given’, ‘When’ or ‘Then’, depending on where it is used. The text written in the scenario becomes the attribute value within the step definition
Having a single step definition for each step of the scenario is wasteful, making maintenance difficult and doesn’t comply with the DRY principle, the attribute text of the two ‘Given’ methods are nearly the same, the only difference is the entered values, we can combine these two steps into a single code step using a simple regular expression.
this single given step now works for both the ‘Given’ and the ‘And’ steps in the scenario, the text in the feature is automatically converted in to an ‘int’ for us, ready for the for use within the code.
I can do the same with the ‘Then’ step, so that I can read the expected result.
At this point NUnit reports one inconclusive test and no missing step definitions and I am ready to start coding.
Before I continue though I want to share some guidelines I have developed over time with regard to writing the feature text, and scenarios.
Getting the feature text right, before writing any step definitions is well worth the effort, it is a lot easier to edit the text before the step definitions are written, rather than trying to edit both sets of files later.
1. I use the narrative section of the feature file to describe the application and what this particular feature file is going to cover, all very high level and non technical, this will be my application documentation in the future so I want it to be expressive and clear as to what each feature covers.
2. I get all the feature files written even if only in draft form, before writing any step definitions. these features define the application, and having the overall view helps guide the development process, helps remove duplication and can help guide the creation of the step definitions.
3. Once I have the feature text complete, I look at the sentence structure to see if there are places I can make them generic, I am thinking about the step definition process at this point, I want to reduce the number of steps to as few as possible, whilst maintaining the scenario uniqueness’s, if you have more than one feature file complete I try to look across features to reduce the step definition count.
Keeping the step definition count to as low as possible makes maintenance easier, because these tests cover a large part of the application they can become complex very easily, this must be managed, so that future maintenance is as easy as possible, I use the normal clean code practices to keeping methods small, with a single responsibility.
Coding the steps is now fairly easy, we only write the test code at this point, and only just enough production code to enable the application to compile.
Notice how at this point my production code is actually in the test code base, I can move it easily later using Resharpers Move_to command. Another thing to notice is that I use field variables to store state between the various scenario steps, SpecFlow does contain a context bag which you can use to store state, I just prefer at the moment to use something I can control.
This test of cause actually fails at the moment with a not implemented exception which is what I expect. Now I have some choices,
If the code required to make the test is going to be complex then I will drop down into Machine Specifications, using the scenario as my requirement guide, and write TDD style tests to drive the required functionality, more of that in the next post!
But as in this case the code required is simple to implement or is simply calling other methods on already written classes, (A typical case for web page code) then I will simply write that code here, make the feature pass, and then move the passing production code up to the production project.
In some cases it may be a combination of the two processes that complete the whole feature, the idea is to use the best tooling to get the job done,
Because SpecFlow has such a light touch, and can be made so expressive, it is worth writing a simple feature file for most projects, using the feature to focus the mind on the problem at hand, which makes the final code easier to write, and the feature file can act as the documentation for the project.
Next time a quick overview of Machine Specifications,