BDD with SpecFlow

Behavior Driven Development (BDD) is about defining the system as a collection of behaviors and then let these behaviors drive rest of the development work. Building on my previous post , this post will have us dive deeper into the concepts of BDD. In order to understand BDD better and see the some of the concepts around it in real action, we will use a popular tool called SpecFlow from TeckTalk. Tools like SpecFlow facilitate communication between the business experts and the developers by allowing them to use a common platform to define executable system behaviors.

Before we jump into SpecFlow, let us get some of the terms and nomenclatures around this tool straightened. We will be using some of these terms over and over again in the course of this post. Two such very important terms are Feature and Scenario.

Feature – a logical unit of functionality which has a business value. For example, the ability to add a customer to the system is a feature, or the ability to send an email with the product catalog to a customer can also thought to be another feature. Creation of the “CUSTOMER_MASTER” table in the database in not a feature.

Scenarios – different conditions around a feature and the system’s expected behavior against these conditions. For example, if the customer is successfully added to the system, the user should be taken to customer-list page. If the customer is not successfully added then the user should remain in the same page and the reason of failure must be displayed.

In order to understand the idea of Feature and Scenario better, let us use an overly simplified feature for an example. Let us assume that we want to build a feature called “Customer Addition”. As the name suggests, we intend to develop a Feature which will allow the user to add a customer to the system. Let’s say we come up with two scenarios – First, when the user is successfully added to the system, and second when the user is not successfully added to the system.

SpecFlow uses  english-like language called Gherkin to write these Features and Scenarios. Gherkin is a DSL(Domain Specific Language) and hence can be understood by the Business folks and the SMEs quite easily. Gherkin uses .feature file to specify a Feature. The Feature keyword marks the beginning of a feature. For more details on the syntax of Feature see this link. This descriptive text in nature and is used to describe what the feature is supposed to do. It need not necessarily follow a particular convention or pattern. SpecFlow recommends using the following template though.

In order to [reason]
As a [role]
I want to [functionality]

A Feature typically consists of one or more Scenarios. The scenarios must follow the Given-When-Then syntax,

Given – precondition or the state of the System (Under Test) prior to the action
When – action taken
Then – result or the state of the System (Under Test) after the action

Okay! Back to our “Customer Addition” feature. SpecFlow installs few templates in the Visual Studio. One such template is called SpecFlow Feature File and has the .feature extension. Let us create our feature using the SpecFlow Feature File and name it CustomerAddition.feature. In light of the conventions discussed earlier in the post, the feature should look something like this,

Feature: Add a CustomerIn order to maintain the customer’s information
As the authorized user of the system
I want to add a customer to the systemScenario: Customer Added successfully
Given the following customer
|Name  |Phone  |Address    |
|Rob  |678-826-6675 |514 M cricle, Atlanta, GA 30328 |
When I click “Add”
Then go to the customer-list page and display the added customer

Scenario: Customer not Added successfully
Given the following customer
|Name  |Phone  |Address    |
|Jane|678-826-6675 |120 Park Dr, GA 30300 |
When I click “Add”
Then stay in the same page and display the error

What is actually happening here is that every time the Feature file is saved, SpecFlow parses it and generates a code-behind file for it. Under the hood, all this generated piece of code essentially does is call few methods (tests) for these Given, When and Then statements. If we go ahead and try to run our Feature file (using MSTest or NUnit) at this point, we will see that SpecFlow is complaining that it does not find a matching step definition for the Given, When or Then statements.

   
No matching step definition found for the step. Use the following code to create one:
    [Binding]
    public class StepDefinitions
    {
        [Given(@”the following customer”)]
        public void Given(Table table)
        {
            ScenarioContext.Current.Pending();
        }
    } 

Let’s go ahead and add something called the SpecFlow Step Definition file from the Visual Studio. A Step Definition File tells the runtime which method (step) should be executed for a Given or When or the Then statement. This wiring up is done by the [Binding] attribute that decorates the StepDefinition class. If our Step Definition Class were called the CustomerAdditionStep, then using the generated code in the error message we can create a class which would look like the following,

   
    [Binding]
    public class CustomerAdditionStep
    {
        [Given(@”the following customer”)]
        public void Given(Table table)
        {            
            // …..
            //Implement the tests and asserts here
         }
    }
 

We can write tests and assertions using these methods and automate a business scenario using these step definitions.

This is a very simple demonstration of how a tool (SpecFlow in this example) can be used to provide a common platform for both business and the development folks to be able to collaborate, develop a shared understanding of the system and then be able to automate that shared understanding. In other words, SpecFlow allows the devs and the BAs to collaborate and define executable behaviors for the system (in terms of scenario) and then let these set of behaviors drive the development of rest of the system.

Advertisements

Get Your TDD Right with BDD

If you have been using TDD (Test Driven Development) or even maintaining unit-tests at some level, then probably you have already been using these tests as a means to express the business requirement. Writing unit tests before writing the actual implementation code is undoubtedly a very good exercise to brainstorm and understand problem before making an attempt to solve it. But for developers who are writing these tests, there is always a chance of missing out something of business importance or misinterpreting a business requirement. In other words, though these tests might be good for many things but they hardly make any attempt to bridge the age old gap between the business needs and the code development.

Another ailing thing about TDD is the name itself. ‘Test’ driven development is hardly about testing. It has never been about doing the tester’s job. Many people would say TDD is and has always been about good design. I do not completely agree with that either. Good design is a very good by-product of TDD, but that’s not the primary purpose of TDD. The very name and the nomenclature around it, words like Test, Assertion etc, influences the brain (Sapir–Whorf hypothesis) compels it to think that TDD has got something to do with testing.

TDD also requires a fundamental shift in focus as a developer. For decades we developers have been thinking about those grand software designs up-front, creating the databases, the data-access classes, the business facades, re-usable components and what not before addressing the actual business needs in small bits. TDD done right demands for a drastic change in this mindset. It requires the developer to think about the business needs first. Pick a very tiny slice from it which still has a business value and write only as much code that is required to implement this piece of business value. Really, this might not be the most intuitive thing to do for most of the developers. Moreover, this ‘no up-front design’ idea (though I do not completely agree with it) does not work in the best interest of someone like me who sell themselves as ‘Architects’. Pun intended!

No wonder so many teams struggle to get TDD right.

Due to some of these inherent problems with TDD and the huge gray area without sufficient guidelines on what and how much to test, people like Dan North came out with the idea of BDD a.k.a. Behavior Driven Development. The idea behind BDD is pretty simple. The idea is to provide a common tool and guideline to both the business and development folks. This tool/guideline would allow the business analysts and SME’s to write the business requirements (in a specified format) using english-like language. They would write the different business scenarios around the requirement. In other word, they would define the ‘Behavior’ of the system. The same tool would be able to generate or at least guide developers write the test-cases from these scenarios. The developers would implement these test-cases one by one and make all the tests go green. And TADA! In a perfect world, you have a business requirement translated into a working code.

With BDD the point really is to be able to write tests which are more relevant. Tests which matter. Tests which are derived right out of the business requirements and scenarios, coming right out of the horses mouth. BDD is about putting some more structure and discipline into the Test Driven practices you already claim to do.

Story about User Stories

It’s amazing how people somehow manage to figure out ways to abuse systems that they once so passionately fought to bring in. I recently came across a user story card which had the whole sequence diagram scribbled on it in an extremely small fonts. Interesting work-around, isn’t it? For those who have not seen one, a user story card is typically a 3×5 index card used by many organizations to represent a user story.  The small size has been selected for a reason. The idea behind having a 3×5 index card is to constraint the user story to short and simple.

But user story card is just a part of the story. Let us try look at the whole story itself. Please allow me to tell you the story of user stories.

A user story describes desired functionality from the business perspective; it is the user’s story. A good user story describes the desired functionality, who wants it, and how and why the functionality will be used. I completely agree with Mike Cohn’s favourite Template for writing user story which are short and simple,

As a [user role]

I want [functionality]

So that [reason]

 A user story is comprised of:

1. Card – the written description of the story, serves as and identification, reminder, and also helps in planning.

2. Conversation – this is the meat of the story; the dialogue that is carried out with the users; recorded notes; mockups; documents exchanged.

3. Confirmation – the acceptance test criteria that the user will utilize to confirm that the story is completed.

A very good guideline for writing good user stories is the INVEST model

Independent – One user story should be independent of another (as much as possible). Dependencies between stories make planning, prioritization, and estimation much more difficult. Often enough, dependencies can be reduced by either combining stories into one or by splitting the stories differently.

Negotiable – A user story is negotiable. The “Card” of the story is just a short description of the story which do not include details. The details are worked out during the “Conversation” phase. A “Card” with too much detail on it actually limits conversation with the customer.

Valuable – Each story has to be of value to the customer (either the user or the purchaser). One very good way of making stories valuable is to get the customer to write them. Once a customer realizes that a user story is not a contract and is negotiable, they will be much more comfortable writing stories.

Estimable – The developers need to be able to estimate (at a ballpark even) a user story to allow prioritization and planning of the story. Problems that can keep developers from estimating a story are: lack of domain knowledge (in which case there is a need for more Negotiation/Conversation); or if the story is too big (in which case the story needs to be broken down into smaller stories).

Small – A good story should be small in effort, typically representing no more, than 2-3 person weeks of effort. A story which is more than that in effort can have more errors associated with scoping and estimation.

Testable – A story needs to be testable for the “Confirmation” to take place. Remember, we do not develop what we cannot test. If you can’t test it then you will never know when you are done. An example of non-testable story: “software should be easy to use”.

So the moral of the story is this. User Stories being the cornerstones for Agile development, deserve their fair share of time, effort and most importantly prudence to be “invested” in them in order to lay a strong foundation for project.

Test Driven Development

As a software developer I always found it very embarrassing to face the truth that my code is also entitled to have its share of bugs. I would find it so very irritating when I have worked passionately for hours to build something and a tester would walk-in with a sheet in hand and suggest “hey bro! You missed out”. I might argue with him but deep down inside I would know the fact that I have indeed “missed out” on something. This is one embarrassment we developers go through all the time but it is only us who could be blamed for this. We don’t think enough before jumping into the code.

There have been so many instances where I have felt like rewriting a piece of code which has become ugly over a period. These code would smell. But my boss would silence my itch with a question that “why would you want to finger something which is up and running?”.

While these problems had become a way of life for me, I came across a refreshing way of software development – Test Driven Development (TDD). TDD is a process pattern for constructing iterations of development projects that employ unit testing. It is a core tenet of “Agile Development”, specifically the Extreme Programming (XP) camp. Unlike the conventional approach to software development where coding is followed by testing, TDD requires to have the tests in place before writing any code. These test-cases serve as the specification and scope for the functionality to be provided.

TDD Life cycle

Add a test: Add a new test. The test must fail for the first time as because the test must be created before any the functionality itself.

Run the test: The test must fail for the first time.

Write code: Write code to develop the functionality.

Run the test again: All the test written for the functionality must pass indicating that all specifications have been met. If not, refactor the code until all the tests pass.

TDD requires developers to think and think hard about specification and scope of the functionality to be developed before writing any code. This ensures that a good deal of brain storming going into understanding the problem before making any efforts to solve it.
Refactoring code is a risky affair because you can always run into this risk of “breaking something while making something”. Having unit-tests in place gives developers the cushion to refactor code confidently. After making the code change the developer can simply run the automated test and to ensure that everything is alright.

Coding for testability demands a much more civilized design to be in place. The code must have “Separation of Concerns” clearly defined. It must be orthogonal. It must follow “Dependency Inversion” Principal. A code not easily testable simply suggests a flaw in the design.

As a newbie, I found writing TDD a little time consuming and cumbersome. But as I get more and more used to it I can really see an increase in my productivity and improvement in the quality of code that I write. The benefit that I reap by investing a little extra time is huge. It’s definitely worth a shot.