Getting started with Behavior-Driven Development in ASP.NET

By now, almost all .NET developers are familiar with Test-Driven Development, or “TDD” – the iterative software development technique has been around for about 10 years now, and being often associated with Agile development has kept it in circulation.

This of course means that we need new, lesser known acronyms to talk about – so let’s dive into BDDBehavior-Driven Development.

Behavior-Driven Development is based off of Test-Driven Development and aims to unite software developers and business analysts with a common toolset for both defining and testing an application. It’s popular because it breaks down barriers between teams and enables a ‘ubiquitous language’ for communicating and testing specifications.

In many large development projects, there are three “sources of truth” used to compare an application to the desired functionality:

  1. Business analysts create requirements documents for all site features. They use these to write test scripts and the developers refer to them for specifications.
  2. The functional testing team has written test scripts from the requirement documents to test the entire application. They use these to generate bug reports.
  3. The development team has created unit tests and possibly automated browser tests that require development tools and skillsets to run. They use these to verify correctness against the requirements.

If you’ve been on a project with all of the above, then you’ve probably seen issues like these:

  • The test scripts make some assumptions about functionality not completely fleshed out in the requirements. The development team makes different assumptions, so bugs end up logged against the discrepancies.
  • A new feature makes its way into the requirements. It hasn’t been developed yet, so its absence isn’t discovered until the testing team has time to update the test scripts. The developers need to update their tests to stay up-to-date as well.
  • Developers run all their tests and believe everything’s working as intended, but have no way to be sure the testing team will also approve their fixes.

These aren’t intentional problems – they’re just what happens when a team gets busy. However, though unintentional, all of these lead to rework, confusion, uncertainty and worst of all – meetings. Behavior-driven development aims to solve these issues by unifying the three ‘sources of truth’ identified above – though requirement documents often can’t be avoided, we can at least merge together the functional and technical testing approaches. Let’s take a look at what this process involves.

BDD in the Development Process

To start with, let’s discuss integrating BDD into the development process. Here’s a quick look at how to set up a ASP.NET project with a BDD testing approach using Selenium, an automated browser testing framework and NBehave, a BDD framework:

  1. Write tests
  2. Set up a test project
  3. Write C# code using Selenium to run your steps and map them using NBehave
  4. Write unit tests that use NBehave to execute your tests

Step 1: Write Tests

BDD tests are almost always written in a language called Gherkin – it’s designed to be human-readable and machine-parseable, while able to easily describe business functions.

Here’s a simple example – this illustrates the easy-to-read nature of Gherkin.

Feature: Wikipedia
Find out if we are on Wikipedia.

    Scenario: Load Wikipedia
        Given a browser
        When I visit "http://www.wikipedia.org"
        And I fill in "search" with "West Monroe Partners"
        And I press "go"
        And I wait for 2 seconds
        Then I should see "West Monroe Partners LLC"

We’ve got Features, which describe a feature an application has, and then different Scenarios that test this feature. Within each feature are a set of Steps.

Take note of all the different steps we have here:

  • I visit <site>
  • I fill in <field> with <text>
  • I press <button>
  • I wait for <x> seconds
  • I should see <text>

We’ll be defining these in code in step 3. For now, save this in a file called “wikipedia.feature” and let’s set up our actual project.

Step 2: Set up a test project

In general, we want to create a standard unit test project and install the NBehave and Selenium packages – here’s a step-by-step guide (for VS2012):

  1. Create a new project in your solution – use the Unit Test Project template.
  2. Right click on the project and go to ‘Manage NuGet Packages’.
  3. Search for NBehave in the Online section and install the basic NBehave package.
  4. Next, search for Selenium WebDriver* and install that package as well.

Testing in Internet Explorer? Take a look at IEWebDriver. Be warned – it’s slower than other ‘drivers’.
You’re all set! We can now start building our tooling – the code that will support our BDD testing approach.

Step 3: Write C# code using Selenium to run your steps

Each line of the Gherkin tests that starts with ‘Given’,’When’,’And’, or ‘Then’ is considered to be a step – either a condition, an action, or an expected result. We must define these steps in order to run our test. Here’s a quick sample:
Refer to the NBehave documentation for some more information on the attributes used here.

//A class defining action steps
[ActionSteps]
public class SeleniumSteps
{
    //Reference to the WebDriver - the object "driving" interactions with the browser.
    // This object will launch the browser automatically as well.
    public IWebDriver driver;

    //The step definition this function matches
    [Given("a browser")]
    public void GetBrowser()
    {
        driver = NBehaveUtils.GetDriver(); //custom function, see source code provided later
        Assert.IsTrue(driver != null);
    }
    //Steps can match more complicated patterns - $website will be passed to the function as the website variable.
    [When("I visit \"$website\"")]
    public void VisitUrl(string website)
    {
        driver.Navigate().GoToUrl(website);
    }

    ...

}

Once all steps are defined, we’re almost ready to go – however, there are some other things we need to take care of that steps don’t explicitly handle. For instance, you’ll need to launch the browser to perform tests, and you might want to close the browser after every scenario. These things are handled by NBehave’s Hooks system:

//Denotes a class that contains hooks for NBehave
[Hooks]
public class SeleniumHooks
{
    private IWebDriver driver;

    [BeforeFeature]
    public void SetupFeature()
    {
    //Nothing before a feature
    }

    public void TearDownFeature()
    {
    //Nothing after a feature
    }

    [NBehave.Narrator.Framework.Hooks.BeforeScenario]
    public void SetupScenario()
    {
        //Use FireFox driver
        driver = new FirefoxDriver();
    }

    [NBehave.Narrator.Framework.Hooks.AfterScenario]
    public void TearDownScenario()
    {
        if (driver == null)
        {
            return;

        }
     //Close the browser after running a scenario
     driver.Close();

    }
}

You’ll want to write some helper functions to handle all of the actual browser interaction too- in the sample project below you can find some utility and helper classes I wrote to handle element location and interaction.

Step 4: Write unit tests that use NBehave to execute your tests

So, after you’ve set up your test project, defined all your steps and gotten Selenium integrated, the only thing left to do is run the original tests. There are a few ways to do this in NBehave, but here’s how I do it:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NBehave.Narrator.Framework;

namespace BrowserTests
{
    [TestClass]
    public class BrowserTests
    {
        [TestMethod]
        public void RunTestFeature()
        {
            @"tests/test.feature".ExecuteFile();
        }
    }
}


Here, we’re executing NBehave’s ExecuteFile method on the file path – using a String extension method is kind of messy but it means we can use the file without having to convert it to C#. You can also programmatically define features and run them that way, but in order to achieve our ‘ubiquitous language’ goal it’s better if we can share the exact same test files with everyone.

When you run the test, NBehave will parse each step using the step code you wrote – that same code will launch Selenium and run your scenarios. From there the Unit Test system will determine if the test passes or fails based on your ‘Then…’ step definitions.

(If you’d like to get a head start on this, I’ve uploaded a ‘starter kit’ of the code you’ll need to get this working on GitHub: https://github.com/tnubel/BDDBrowserTesting . Take a look!)

BDD in Requirements and Functional Testing

In order to practice ‘true’ BDD, everyone on the team involved with the application should be utilizing the same set of tests. If your project is already underway, getting everyone to switch to your fancy new Gherkin format is quite difficult – you’ll need to write some yourself to demonstrate the benefits. If you have one major ‘flow’ in your application (like an Order process), start with that.

Gherkin tests can be run automatically by the testing team – in the GitHub repository I mentioned in the previous section, there’s a “stand alone” testing application that can run Gherkin tests without any installation or pre-existing developer tools. If you have a tedious task like an order form you’d like to test multiple times, this application can be deployed onto any machine and vastly expedite testing.

Here are some things to keep in mind when writing tests:

  1. Use a limited vocabulary. Boil down the interactions that happen on your site to as few as possible – if you have a non-standard interaction that goes beyond filling in a field or clicking a button, discuss the best way to describe it with your team.
  2. Abstract away concepts that don’t deal with the requirements – the ID of a button changing shouldn’t break a test, so avoid specifying it if possible.
  3. Avoid absolute URLs – if you have multiple environments to test on, having to change the script each time to ‘point’ to the new environment gets old fast. Try and work out a system development-side to specify the URL outside of the feature file.
  4. Keep a shared repository of tests in source control like Git or SVN – this way all users can check in their changes. In my experience, the biggest challenge BDD faces is keeping tests updated, and the way it can be overcome is by eliminating all duplication.

Conclusion

Behavior-driven development represents an evolution of test-driven development that seeks to include the entire team in the development process. As projects become more and more complicated and less about any given line of code, any methodology that can help decrease team segmentation deserves to be looked at. While this blog doesn’t cover BDD in any respectable amount of detail, I hope it provides a solid foundation upon which to experiment. Thanks for reading!

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

Phone: 312-602-4000
Email: marketing@westmonroepartners.com
222 W. Adams
Chicago, IL 60606
Show Buttons
Share On Facebook
Share On Twitter
Share on LinkedIn
Hide Buttons