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

Using the underscore step definition format we would end up with step definitions something like this:

using TechTalk.SpecFlow;

namespace ContextInjectionExample
{
    [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.
        }
    }
}

Whatever parameterised name is used in the Given step, we need to be able to use this in the Then step to assert that the contact list does in fact contain the new name.

To use Context Injection to do this, we first define a class to hold the new contact details:

public class NewContactDetails
{
    public string Name { get; set; }
}

This class represent the “context” that we want to be able to share between step definition code.

The next step is to be able to access this context in all our steps in all our step definition files. To do this we create a constructor that has a parameter than represents our context, and store the object that SpecFlow auto-injects into this, in a local field in our steps class:

private readonly NewContactDetails _newContactDetails;

public SomeFeatureSteps(NewContactDetails newContactDetails)
{
    _newContactDetails = newContactDetails;
}

Now we have our context, we can use it in our step definitions. We can set properties in the Given step:

[Given]
public void Given_I_have_entered_NEWNAME(string newName)
{
    _newContactDetails.Name = newName;
}

And then read the property values in our Then step:

[Then]
public void Then_the_contact_list_should_show_the_new_contact()
{
    var nameToCheckExists = _newContactDetails.Name;
    // etc.
}

To learn more about Context Inject, check out my SpecFlow Tips and Tricks Pluralsight course.

You can start watching with a Pluralsight free trial.

SHARE:

Comments (8) -

  • Marcus Hammarberg

    12/2/2013 6:50:49 PM | Reply

    Hi,

    great stuff! More people need to know about the more advanced features of SpecFlow so that we can start to write maintainable step definitions. SpecFlow gets a lot of bad reputation due to the fact that it's hard to maintain the steps.

    I've used the Context Injection feature to inject my driver objects, to great use for me and teams I've been part of: www.marcusoft.net/.../...extInjectionSpecFlow.html

    Keep the great work up!

  • Logan

    12/3/2013 9:27:32 AM | Reply

    Hi Jason

    I do this by creating a BaseStepDefinition class to hold a static instance of ALL data classes that needs to be shared across different steps. All step definition classes will then by default inherit the base step definition class.

    Very good post. Thanks

  • Jason

    12/3/2013 11:08:35 AM | Reply

    Thanks Marcus, thanks Logan Smile

  • David Wood

    12/7/2013 7:36:11 AM | Reply

    Took me months to try injecting context into other contexts. Works perfectly and makes my step definitions much more readable and refactorable.

  • Jason

    2/14/2014 3:17:59 PM | Reply

    Just released my new SpecFlow Tips and Tricks course that covers Context Injection and other things : http://bit.ly/psspecflowtips

  • miya

    12/10/2018 8:49:01 PM | Reply

    Awesome. Very clear,thank you Jason.

    • Jason Roberts

      12/12/2018 2:16:13 AM | Reply

      No worries miya - glad it is of use Smile

  • Siva

    12/20/2018 2:20:08 PM | Reply

    Is there any reason  to use readonly for the newcontactdetails?  Even without readonly it works. Just trying to understand, Jason. And to my wonder this NewContactDetails newContactDetails is carried successfully to other step definitions too!  Could you please explain?

Add comment

Loading