3 Ways to Pass State Between SpecFlow Step Definitions

Sometimes we need one step definition to know about parameter data that was passed to previous steps.

There’s 3 ways main ways to do this, each with various considerations.

Private Field in Binding Class

This is the simplest approach. Simply add a private field to your [Binding] class containing your step definitions.

In a step, just grab the parameter data and store it in this private field.

In later steps, retrieve the data from this private field.

This approach is simple but breaks down when we start to refactor our step definitions into multiple step definition classes; the private field data is not accessible between steps in different binding classes.

ScenarioContext

We can store data for the current executing scenario using the ScenarioContext class.

There's a number of ways to use it, but essentially it’s a dictionary that we can store arbitrary data and retrieve it by a key:

ScenarioContext.Current["age"] = 42;

This approach can be used even if we refactor step definitions out across multiple binding classes. The scenario context is shared between all steps for the lifetime that a scenario is executing.

This approach can start to get a little ugly, we also have to make sure our dictionary keys are correct in all the steps where we set or retrieve data.

By default, it’s also weakly-typed – the dictionary just stores objects so we can end up with casts every time we retrieve data.

Context Injection

The third method (which I wrote about previously) lets us take a dependency injection style approach, and define POCOs to represent the data (in a strongly typed way) that automatically gets injected into each of our binding classes.

Like ScenarioContext, this approach also works across multiple binding classes. Unlike ScenarioContext, we don’t have to worry about dictionary keys or casting.

 

If you’re new to SpecFlow and Gherkin, check out my Pluralsight course:  Automated Acceptance Testing with SpecFlow and Gherkin or if you understand the basics or have been using it for a while, check out  SpecFlow Tips and Tricks course to learn how to create more maintainable SpecFlow test automation solutions.

New Pluralsight Course: SpecFlow Tips and Tricks

My latest Pluralsight course was released today: SpecFlow Tips and Tricks is a short course to help those who are relatively new to SpecFlow and those who have been using it for a while and want to create more maintainable testing solutions.

The course focuses on 3 main areas:

  • Steps and Bindings
  • Hooks and Scoped Bindings
  • Step Parameters and Data Tables

This course is a loose follow-up to my previous Automated Acceptance Testing with SpecFlow and Gherkin course that covers the Gherkin DSL and other fundamental SpecFlow topics.

You can check out the course on the Pluralsight website or on my author page.

SpecFlow Cheat Sheet

SpecFlow is a tool that allows the writing of business-readable tests that can then be automated in code. If you’re new to SpecFlow check out my Pluralsight course or the resources page.

The cheat sheet below shows the basics of different step binding styles, the hooks that can be used to execute additional code, and scoped bindings.

More...

Advanced SpecFlow: Custom Conversion of Step Parameters and Data Tables with [StepArgumentTransformation]

SpecFlow is a tool that allows the writing of business-readable tests that can then be automated in code. If you’re new to SpecFlow check out my Pluralsight course or the resources page to get up to speed before looking at these more advanced topics.

SpecFlow will attempt to perform some conversions of step arguments as specified in the documentation.

We can also tell SpecFlow to use our own custom conversions. Take the feature below:

Feature: SomeFeature

Scenario: Update User Password
    Given The original user was created over 10 days ago
    When I update the users password to "some password"
    Then I should see the following errors
        | ErrorCode         | ErrorDescription          |
        | 442               | Out of date user          |
        | 28                | Changes were not saved    |

From this we generate some basic step definitions:

[Given]
public void Given_The_original_user_was_created_over_DAYS_days_ago(int days)
{
}

[When]
public void When_I_update_the_users_password_to_NEWPASSWORD(string newPassword)
{
}
       
[Then]
public void Then_I_should_see_the_following_errors(Table table)
{            
}

Automatically Parsing 10 Days Ago into a DateTime

In the Given step we get an int specifying how many days ago the user was created. As it’s the Given step we need to put the system into a state where the user creation date, for example held as a DateTime in the user database, is 10 days old. If this is just a single step then we can simply write the code to subtract a number of days from todays date in the step itself. Note: this kind of date based testing where we rely on “now” may prove brittle, imagine the a Given ran just before midnight, but the Then gets executed after midnight, i.e. the next day.

More...

Gherkin Cheat Sheet

Gherkin is a Business Readable Domain Specific Language. It allows the documentation of what a system should do in natural language (multiple languages are supported) and allows test automation code to be written for the system’s features.

This cheat sheet outlines the language basics.

More...

Advanced SpecFlow: Restricting Step Definition and Hook Execution with Scoped Bindings

SpecFlow is a tool that allows the writing of business-readable tests that can then be automated in code. If you’re new to SpecFlow check out my Pluralsight course or the resources page to get up to speed before looking at these more advanced topics.

Step definitions and hooks by default have global scope within the test project.

For example, take the following feature:

Feature: SomeFeature

Scenario: Scenario 1
    Given A
    When B
    Then C

Scenario: Scenario 2
    Given A
    When X
    Then Z

Here the “Given A” step shares a step definition, note in the following code there is only one step that matches “Given A”:

[Binding]
public class SomeFeatureSteps
{
    [Given]
    public void Given_A()
    {
        // etc.
    }       

    [When]
    public void When_B()
    {
        // etc.
    }
    
    [When]
    public void When_X()
    {
        // etc.
    }
    
    [Then]
    public void Then_C()
    {
        // etc.
    }
    
    [Then]
    public void Then_Z()
    {
        // etc.
    }
}

If for some reason we want different automation code to run for each of the “Given A” steps, we could simply reword one of the steps, then we would have two different step definitions.

More...

Advanced SpecFlow: Using Hooks to Run Additional Automation Code

SpecFlow is a tool that allows the writing of business-readable tests that can then be automated in code. If you’re new to SpecFlow check out my Pluralsight course to get up to speed before looking at these more advanced topics.

In addition to executing test automation code in step definitions, SpecFlow provides a number of additional “hooks” to allow additional code execution at various points during the test execution lifecycle.

For this example, consider the following feature:

Feature: SomeFeature

Scenario: Add New Contact Name
    Given I have entered Sarah
    When I choose add
    Then the contact list should show the new contact

With the following step definitions:

using TechTalk.SpecFlow;

namespace SpecFlowHooks
{
    [Binding]
    public class SomeFeatureSteps
    {
        [Given]
        public void Given_I_have_entered_NEWNAME(string newName)
        {
            // etc.
        }
        
        [When]
        public void When_I_choose_add()
        {
            // etc.   
        }
        
        [Then]
        public void Then_the_contact_list_should_show_the_new_contact()
        {
            // etc.
        }
    }
}

When the scenario is executed we get the following test output:

More...

Advanced SpecFlow: Sharing Data Between Steps with Context Injection

SpecFlow is a tool that allows the writing of business-readable tests that can then be automated in code. If you’re new to SpecFlow check out my Pluralsight course to get up to speed before looking at these more advanced topics.

Individual step definitions that represent the natural language scenarios are separate methods that get executed. Often we need to pass data between these steps. The simplest approaches to get started with are to use simple fields in the class containing the steps or to use the Scenario Context. An alternative to these approaches is to use Context Injection.

For example, imagine the following scenario:

Feature: SomeFeature

Scenario: Add New Contact Name
    Given I have entered Sarah
    When I choose add
    Then the contact list should show the new contact

More...




Automated Acceptance Testing with SpecFlow and Gherkin Course

With my new Pluralsight course you’ll learn how to narrow the gap between the business/customer and the development team by creating business-readable, automated tests.

The course covers how to install SpecFlow in Visual Studio, the Gherkin business-readable domain specific language (DSL), and how to create code-automation from this natural language.

You can find the course on my Pluralsight author page.

Creating Inline Data Driven Tests in xUnit

xUnit.net allows the creation of data-driven tests. These kind of tests get their test data from outside the test method code via parameters added to the test method signature.

Say we had to test a Calculator class and check it’s add method returned the correct results for six different test cases. Without data-driven tests we’d either have to write six separates tests (with almost identical code) or some loop inside our test method containing an assert.

Regular xUnit.net test methods are identified by applying the [Fact] attribute. Data-driven tests instead use the [Theory] attribute.

To get data-driven features and the [Theory] attribute, install the xUnit.net Extensions NuGet package in addition to the standard xUnit.net package.

Creating Inline Data-Driven Tests

The [InlineData] attribute allows us to specify test data that gets passed to the parameters of test method.

So for our Calculator add test we’d start by defining the test method:

More...