BDD (Behavior Driven Development)

 

In the previous article we looked at how to do Test Driven Development (TDD) while doing the XP (Extreme Programming). In XP, the implementation of the tasks are done in the steering phase of the iteration planning. One of the tenets of the steering phase is “functional tests are run”. In this article we will see how to create functional tests using Behavior driven development (BDD) and its benefits.

Following are the some of the benefits of automated functional tests.

  • Functionality experienced by the User is tested
  • Saves testing time for the developers
  • Test in every environment (Dev, QA, Stage) without much effort
  • Generates confidence in every stake holder

Tools required for doing BDD in .Net

There are various tools available to do BDD in .Net. I have listed few of them below

SpecFlow is one of the most popular tools used in the .Net/C# community. And in this blog lets use the same. The tool comes as a Visual Studio Extension and can be downloaded directly from VS.

Creating a SpecFlow Project

Once SpecFlow extension is installed, the template required for doing BDD will be installed.

  • Create a simple “Class Library” Project in Visual studio
  • In the project, create a SpecFlow Feature file

Selecting the test framework

Before we Create/execute the scenario, we need to wire the SpecFlow with a compatible test framework. To do that we need to make changes to the app.Config file of the project.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="specFlow" type="TechTalk.SpecFlow.Configuration.ConfigurationSectionHandler, TechTalk.SpecFlow" />
  </configSections>
  <specFlow>
    <!-- For additional details on SpecFlow configuration options see http://go.specflow.org/doc-config -->
  <!-- For additional details on SpecFlow configuration options see http://go.specflow.org/doc-config -->
    <unitTestProvider name="xUnit" />
  </specFlow>
</configuration>

In this example we are using XUnit as the testing framework. SpecFlow supports a series of testing frameworks and more details can be found here.

Creating the Behavior

Now, let us look at how to create a functional test using behavior driven approach. Let’s consider the following story while creating a POS (point of sale) application for a super market.

“As a Supermarket POS app developer,  i would like the API to Give the total amount while billing so that I can wire up API against the UI.

Let’s write the Behavior required in order to implement the above API requirement .

Feature: SuperMarketProductsAPI
	As a Supermarket Biller 
	i would like the API to
	Give the total amount while billing
@SmokeTest
Scenario: Find the total amount while billing
	Given Shopping cart is filled with all the items required by consumer
	And Campaign information for the month is available in the system
	When I pass the cart to create bill API
	Then the total bill amount should be calculated

The above specification is written using the custom language (testing DSL) create by the specflow.org. (Please read about what is DSL here.)

There are 2 parts to the above Specflow specification

  • Feature – Denotes bigger context (description/story) of the application
  • Scenario – Specific workflow or behavior of the system under the feature. Each scenario has the following sub-parts
    • Given, And – describes what we already assumed available
    • When – The specific action which will trigger the workflow/behavior
    • Then  – expected behavior

 

Creating step definitions

When we run the unit test corresponding to the above test we it will fail as there are no definitions corresponding to the above scenarios.

Now Right Click on the feature file and select “Generate step Definitions”

You will see the pop-up like below, select “Generate” and then “Save” the file.

The file will have the details about “what SpecFlow should do when test is executed”.

using System;
using TechTalk.SpecFlow;

namespace SuperMarketFunctionalTests
{
    [Binding]
    public class SuperMarketProductsAPISteps
    {
        [Given(@"Shopping cart is filled with all the items required by consumer")]
        public void GivenShoppingCartIsFilledWithAllTheItemsRequiredByConsumer()
        {
            ScenarioContext.Current.Pending();
        }
        
        [Given(@"Campaign information for the month is available in the system")]
        public void GivenCampaignInformationForTheMonthIsAvailableInTheSystem()
        {
            ScenarioContext.Current.Pending();
        }
        
        [When(@"I pass the cart to create bill API")]
        public void WhenIPassTheCartToCreateBillAPI()
        {
            ScenarioContext.Current.Pending();
        }
        
        [Then(@"the total bill amount should be calculated")]
        public void ThenTheTotalBillAmountShouldBeCalculated()
        {
            ScenarioContext.Current.Pending();
        }
    }
}

When you build the project and execute the test corresponding to this, it will fail. This is because none of the parts of the test (given, when, then) are having implementation.

Writing code to make it work

Now that the behavior has been created, we are good to validate that with the team and implement the code/functionality corresponding to the requirement. Of course using best coding practices like TDD 🙂

Making the behavior test pass

In order to make the behavior test pass we need to write the implementation in the “Step Definition” file.

namespace SuperMarketFunctionalTests
{
    using Newtonsoft.Json;
    using System.Collections.Generic;
    using System.Net.Http;
    using TechTalk.SpecFlow;
    using Xunit;

    [Binding]
    public class SuperMarketProductsAPISteps
    {
        Product P1 = new Product { Name = "test1", Cost = 5 };
        Product P2 = new Product { Name = "test2", Cost = 10 };
        ShoppingCart cart;
        List<Campaign> campaign;
        Bill bill;
        [Given(@"Shopping cart is filled with all the items required by consumer")]
        public void GivenShoppingCartIsFilledWithAllTheItemsRequiredByConsumer()
        {
            cart = new ShoppingCart { Products = new List<Product> { P1, P2 } };
        }
        
        [Given(@"Campaign information for the month is available in the system")]
        public void GivenCampaignInformationForTheMonthIsAvailableInTheSystem()
        {
            campaign = new List<Campaign> { new Campaign { product = P1, discount = 1 } };
        }
        
        [When(@"I pass the cart to create bill API")]
        public void WhenIPassTheCartToCreateBillAPI()
        {
            var client = new HttpClient();
            var response = client.PostAsync("http://myapi.supermarket.com", new StringContent(JsonConvert.SerializeObject(cart))).Result;
            var output = response.Content.ReadAsStringAsync().Result;
            bill = JsonConvert.DeserializeObject<Bill>(output);
        }
        
        [Then(@"the total bill amount should be calculated")]
        public void ThenTheTotalBillAmountShouldBeCalculated()
        {
            Assert.True(bill.totalAmount == 14);
        }
    }
}

Once the code is there we can see the behavior test pass.

Conclusion

BDD is very powerful way of ensuring high code quality in conjunction with business requirement. In Extreme programming (XP) , BDD is considered to be a very important practice where functional tests are mandated to run at least once during the iteration.  Is BDD/Functional tests helping your team/business in achieving success or not ? Do let us know your thoughts.

Leave a Reply

Your email address will not be published. Required fields are marked *