Practical ASP.NET

Stepping Through Binding Styles Using SpecFlow 2

SpecFlow offers a number of binding styles for bridging business-readable tests with test-automation code.

SpecFlow allows the building of a bridge between the business and the development team by allowing the creation of business-readable tests. It does this by allowing the writing of high-level scenarios written in natural language (English, French, German and so on).

SpecFlow scenarios are written in this high-level language that business people, clients and other stakeholders can understand. On their own, the steps in a scenario cannot be executed as tests; they need to be "bound" to test-automation code.

SpecFlow provides a number of binding styles.

In Listing 1, each step in the "Add two numbers" scenario maps ("binds") to a C# method. It's inside these bound C# methods that the automation code is added. It's also worth noting that a single C# method can map to multiple lines (steps) in the scenarios; this allows code reuse and reduces test code maintenance overheads.

Listing 1: A Simple SpecFlow Feature
Feature: Calculator
     In order to make it easier on my brain
     As someone who is not good at mental arithmetic
     I want to use the computer to do basic maths

Scenario: Add two numbers
     Given The calculator is reset 	
     When I enter 40
       And I Add 20
     Then The value should be 60

To generate an initial steps class that contains C# methods representing the scenario steps, the SpecFlow Visual Studio IDE integration can be used. To accomplish this, right-click in the feature file and in the context menu, and choose Generate Step Definitions as shown in Figure 1.

[Click on image for larger view.] Figure 1. Generating Step Definitions

A dialog box will now appear with a number of options as shown in Figure 2.

[Click on image for larger view.] Figure 2. Generating Steps Definition Dialog Box

Notice that one of the options here is the ability to select a steps binding style as shown in Figure 3.

[Click on image for larger view.] Figure 3. Binding Style Selection

Regular Expression Binding Style
The default binding style is the regular expression style. This style uses attributes on C# methods to map them to scenario steps.

Listing 2 shows a generated feature file using the regular expression style for the scenario shown in Listing 1.

Listing 2: Regular Expression Binding
using System;
using TechTalk.SpecFlow;

namespace SpecFlow2Demo
{
  [Binding]
  public class CalculatorSteps
  {
    [Given(@"The calculator is reset")]
    public void GivenTheCalculatorIsReset()
    {
      ScenarioContext.Current.Pending();
    }
        
    [When(@"I enter (.*)")]
    public void WhenIEnter(int p0)
    {
      ScenarioContext.Current.Pending();
    }
        
    [When(@"I Add (.*)")]
    public void WhenIAdd(int p0)
    {
      ScenarioContext.Current.Pending();
    }
        
    [Then(@"The value should be (.*)")]
    public void ThenTheValueShouldBe(int p0)
    {
      ScenarioContext.Current.Pending();
    }
  }
}

Notice in Listing 2 the additional SpecFlow binding attributes applied to the individual methods: [Given], [When], and [Then]. Each of these attributes takes a regular expression as a parameter. If this regular expression matches the text in a scenario step it will be bound to that step.

If the scenario step contains a parameter that needs to be passed to the bound C# method, this can be captured in the regular expression. For example, the step, "When I enter 40," can be reused with different data by making the "40" a parameter that is passed to the C# method. In the regular expression binding style, this parameter can be captured: "I enter (.*)")]. Here, the regular expression (.*) will capture the text "40" and pass it to the method for use in the automation code.

Method Name Underscore Style
The second binding style is the method name underscore style. This style still has attributes applied to methods, but rather than a regular expression doing the matching, the method name itself is used.

Listing 3 shows an example of the underscore style for the scenario in Listing 1.

Listing 3: Underscore-Style Binding
using TechTalk.SpecFlow;

namespace SpecFlow2Demo
{
  [Binding]
  public class CalculatorSteps
  {
    [Given]
    public void Given_The_calculator_is_reset()
    {
      ScenarioContext.Current.Pending();
    }
        
    [When]
    public void When_I_enter_P0(int p0)
    {
      ScenarioContext.Current.Pending();
    }
        
    [When]
    public void When_I_Add_P0(int p0)
    {
      ScenarioContext.Current.Pending();
    }
        
    [Then]
    public void Then_The_value_should_be_P0(int p0)
    {
      ScenarioContext.Current.Pending();
    }
  }
}

Notice in Listing 3 that the name of the method itself matches the text in the scenario. For example, the step text, "Given The calculator is reset," maps directly to the method, "public void Given_The_calculator_is_reset()." Underscores are used here to separate words.

Parameters in the underscore style are mapped by using uppercase tokens. By default these use the P0, P1 and so on style. A custom token name can also be used; Listing 4 shows two ways the "And I Add 20" step can be bound.

Listing 4: Underscore-Style Parameter Passing
[When]
public void When_I_Add_P0(int p0)
{
  // Test code here
}

[When]
public void When_I_Add_NUMBER(int number)
{
  // Test code here
}

Notice in the second method, the method parameter ("number") matches the uppercase token NUMBER in the method name.

Method Name Pascal Case Binding Style
The Pascal case binding style is very similar to the method name underscore style, but rather than underscores separating words, Pascal casing is used instead. Listing 5 shows this style.

Listing 5: Pascal Case Binding Style
using TechTalk.SpecFlow;

namespace SpecFlow2Demo
{
  [Binding]
  public class CalculatorSteps
  {
    [Given]
    public void GivenTheCalculatorIsReset()
    {
      ScenarioContext.Current.Pending();
    }
        
    [When]
    public void WhenIEnter_P0(int p0)
    {
      ScenarioContext.Current.Pending();
    }
        
    [When]
    public void WhenIAdd_P0(int p0)
    {
      ScenarioContext.Current.Pending();
    }
        
    [Then]
    public void ThenTheValueShouldBe_P0(int p0)
    {
      ScenarioContext.Current.Pending();
    }
  }
}

Just as with the underscore style, parameters are represented as tokens, with either P0, P1 and so on, or named tokens.

About the Author

Jason Roberts is a Microsoft C# MVP with over 15 years experience. He writes a blog at http://dontcodetired.com, has produced numerous Pluralsight courses, and can be found on Twitter as @robertsjason.

comments powered by Disqus

Featured

  • AI for GitHub Collaboration? Maybe Not So Much

    No doubt GitHub Copilot has been a boon for developers, but AI might not be the best tool for collaboration, according to developers weighing in on a recent social media post from the GitHub team.

  • Visual Studio 2022 Getting VS Code 'Command Palette' Equivalent

    As any Visual Studio Code user knows, the editor's command palette is a powerful tool for getting things done quickly, without having to navigate through menus and dialogs. Now, we learn how an equivalent is coming for Microsoft's flagship Visual Studio IDE, invoked by the same familiar Ctrl+Shift+P keyboard shortcut.

  • .NET 9 Preview 3: 'I've Been Waiting 9 Years for This API!'

    Microsoft's third preview of .NET 9 sees a lot of minor tweaks and fixes with no earth-shaking new functionality, but little things can be important to individual developers.

  • Data Anomaly Detection Using a Neural Autoencoder with C#

    Dr. James McCaffrey of Microsoft Research tackles the process of examining a set of source data to find data items that are different in some way from the majority of the source items.

  • What's New for Python, Java in Visual Studio Code

    Microsoft announced March 2024 updates to its Python and Java extensions for Visual Studio Code, the open source-based, cross-platform code editor that has repeatedly been named the No. 1 tool in major development surveys.

Subscribe on YouTube