Behavior Driven Development Using Specflow and Cucumber

Software delivery, teamwork, error-prone detection, maintenance, feature development, business requirements, and many things. When you work in an environment with combined all of these, as a team, you have to have a plan to iterate your piece of software safely and precisely. Both written code and expected behavior must be understandable by most of the units in whole company, so that your code can be understandable and meets the requirements of business units. By achieving such a result like this, we apply testings in our software, and expect them to be pass in every delivery. But what is not enough from the point of business is, the tests you wrote has no meaning for them, and they have no idea if it is fitting their requirements or not to give response about status of work. You, giving result of process, and you are the person that having the responsibility of business. But what have told you, may not what you have understand.

tdd

In TDD, test driven development, we mostly focus on unit tests to not to create flaws in software flow. Write so many unit tests, which are covers most of your software, run them every build, or continuously to see anything fails or not. This is an approach for software engineers. There is no valuable information here that you can send to business analysts. Only thing you can do here is, adding tests and coverage results to your delivery pipeline, and see if you are failing or not. But, failing in terms of business rules still might be happen, and you cannot see them.

bdd

 

What BDD offers you here is, that you can also cover expected behavior of the business by writing human understandable test cases, and interpreting them to your unit tests. This way, you are going to write unit tests and still being in TDD, and also these tests give a lot of feedback to business people to show their requirements meets well in this software delivery. This is not only about giving them feedback, it also about not taking the risk of business rule implementations as a software engineer.

 

Here, you may think BDD replaces the TDD, but it is not. You will see it is actually using TDD from a wider perspective, and it is also not a necessity for everywhere in your testings. Where the business touches your code, then you can apply BDD to feel you more safe with coming requirements from business people. Otherwise, you end up with much more workload than you normally do.

ubiquitous-language

The main purpose of applying BDD must be the filling the gap between business and software people. The idea takes some form in mind of the business owner, then it slowly become a feature in your project. Then, the idea must be presented to developer, to the implementer. Thus, as a consequence, your collaboration and communication will be improved both in between team members and teams.

After a brief explanation I want to talk about the usage of BDD by both owner of the idea and implementer of it.

In the software development side, we have some tools and libraries to use BDD. Lets take a look at them.

Gherkin Language

It is actually very simple language created for not programmers to communicate with programmers. Language has just only a dozen of keywords. For using it inside Visual Studio, you can find SpecFlow for Visual Studio extension. After you install that extension you can add feature files from templates.

gherkin

I want to share an example for gherkin syntax:

Cucumber

Cucumber is a parser library for Gherkin Language. It takes feature files and interprets them in it’s related scope. There are many parsers implemented in different languages in cucumber library. One example cucumber parser can be like this:

For example in the above code, we checked every feature file in a given directory and looked for their tags, if it contains a tag  like @UserStory(Something) then we take that information and do some operational work, such as sending an information to Issue Tracking system by using their endpoints. This way, we can dynamically invoke everything about test cases and integrate them with other parties appropriately to our QA and deployment plans.

SpecFlow

SpecFlow is a powerful library written for .NET developers to implement BDD approach to their testing structure. It is mainly creates a bridge between Gherkin Language and your preferred Unit Testing Framework. It auto-generates the unit testing codes about feature files. It is also using cucumber for parsing feature files under the hood.

They have great toolkit and libraries for different purposes. There are some alternatives to SpecFlow, but I think they have not include many integrations as much as SpecFlow offer. One of them is StoryQ, I used to prefer using StoryQ, but I prefer SpecFlow more now.

SpecFlow also has some features to help us and organize our phrases, so we can modify them and reuse in different scenarios. This way we don’t have to implement same test cases again and again. Let’s look at the example in our Calculator Addition.

Assume that we decided to create a calculator on top of this contract:

When we write our scenario steps, we have a test class something like this:

Here you see we have private members and we pass them between scenario steps. We also explicitly defined  implementation of our calculator. This is not only brings the responsibility of knowing implementations, it also increases complexity of our tests by the time our number of objects increased in project.

If we have an interface for a calculator and different implementations on it, then we want to run our test cases over that interface, not directly using implementation. Because, our purpose to write interface is using things by not knowing directly what are they, as we use dependency injection in our code. So, for achieving this, we can update our tests a little like this:

What we do here is, we added a background operation, and we assumed that we have a “basic calculator implementation” on top of some “calculator” interface. We still don’t know that. Also, we updated our scenario little bit to get the variables over their names, then we can “register” and “resolve” them as exactly over their “names” and “contracts”.

At the other hand, when we look at re-written scenario:

Why did we wanted to do this, instead we could left it as is, and how it helped us? We have more lines, but now, we have ability to send many different types of “calculator” to send our scenario steps. This actually increases the usability of test cases and shows you the correct way of real implementation. We intuitively can see there are some dependencies and we resolved in other steps by not touching the implementation. If we would start writing tests by using older version, then we could need a member field of a calculator. By using new steps, we would still able to write tests over interface and use them. Let’s implement the BasicCalculator now:

There we go. We have now an implementation only capable to sum two numbers at once. And I wrote one more implementation like this one:

As you can guess after here, I can simply add a new definition to background and use it with it name in other steps, but in the older version of scenario, we couldn’t able to do it.

And I changed nothing. This is the reasoning behind giving names and resolving them over contracts.

 

There are so many SpecFlow features, and I can go more and more about them. But I think, this one is the one of the most important inside them. Designing the way you write tests is also designing the way you write code. For having this mindset, SpecFlow gives you nice contexts to play inside your own scenario block, or feature block. Creates you a ground level for making your abstractions in your tests.

Extra: Jira Extensions & Integration

As an example for Cucumber, I gave a piece of code that let you to create a conversation between your tests and issue tracker application. In Jira, I used BehavePro for our BDD integration. By using behave pro business analysts can create features from Jira and relate tasks and bugs. There is also an feature file importer for C# in BehavePro but it didn’t match our development plan. So I wrote a small code to connect BehavePro API and integrate with our Acceptance Test project.

Integration simply gets jira connection and target directory with some properties, then it imports tagged feature files to your target directory with adding them to csproj file. You can find the Github link of code in the end of article.

Extra: Document Generation

You did everything OK and you added your acceptance tests to your deployment pipeline. But, in fact, business analyst have still not readable and metric-able information about your tests. So, we need a documentation of our test outputs. Pickles is a free library for generating output documentation in different formats for your tests. There is also SpecFlow+ extra tools with some license price.

With this two lines you pass your tests NUnit and then pass the Nunit output to PicklesUI, then you get html documented output for tests:

I have also wrote some comments about directory design relation between document generation and Git branches in code. You can also define a small script in your continuous delivery pipeline to auto generate this documentation after pushing your branch.

Summary

BDD is great concept. But do not use it only for saying “We are doing BDD”. Great power comes with great responsibility. So, we have to understand it is not only a developer thing. It is a big teamwork. Needs strong collaboration in your company. Everybody must repeat giving feedback for some amount of time to create valuable output and get informative results. When you start it, you gotta stick with it. But end result will be self documentation and protector of the system. Whenever you give a business decision, you’ll see what is affected from every perspective. I remember a word that saying “Being great is doing so many small good things again and again.”. This fits well to BDD.

Github Link of Project is Here.

References:

1- Wikipedia

2- A White Paper

I am csharp developer, mathematics graduated, visionary coder, tennis player, bad english speaker, blog reader, blog writer, and very lazy person. I will be sharing my personal thoughts, experiences, hobbies that I'd like to do and different news that takes my interest as a simple, regular person. Sometimes in English, sometimes in Turkish.