Strongly Typed ScenarioContext in SpecFlow part II

Last time I posted details on my nuget package which supplies strongly typed ScenarioContexts in SpecFlow.

In the comments Darren pointed out there is a way to do this using a generic wrapper which is built into the framework:

ScenarioContext.Current.Set<AnotherComplexObject>(new ComplexObject());
var anotherComplexObject = ScenarioContext.Current.Get<AnotherComplexObject>();

I didn’t realise that this existed and is very useful. This is another good way to skin the same cat.

This is a great solution and will probably work for you. The only small downside is that because it is casting under the covers you have to provide the type that you are expecting/setting through the generic argument. This is probably not a problem but makes the code a little verbose.

The nuget package moves the casting further up the pipeline into the interceptor so you don’t have to worry about it. By the time that you come to use the context the objects have already been cast into your interface type. The downside to the nuget package however is that you have to derive you step definition classes from an abstract base class BaseBinding. In some circumstances this may not be possible and is a nuisance. The reason I had to do it this way is because it’s the only way that I could hook into the object creation pipeline. If there is a better way then please let me know.

Whilst we are on the subject of the StronglyTypedContext I’d like to take this opportunity to point out one more test case for the shared context. It works across multiple step definition classes as can be seen from the code snippet below:

    public interface ISharedContext
    {
        int CustomerId { get; set; }
    }

    [Binding]
    public class MultipleStepDefinitionsOne : BaseBinding
    {
        [ScenarioContext]
        public virtual ISharedContext Context { get; set; }

        [Given(@"I have a step definition file with a scenario context property")]
        public void GivenIHaveAStepDefinitionFileWithAScenarioContextProperty()
        {
            // empty step
        }

        [When(@"I set the property in one step definition class")]
        public void WhenISetThePropertyInOneStepDefinitionClass()
        {
            Context.CustomerId = 1234;
        }


    }

    [Binding]
    public class MultipleStepDefinitionsTwo : BaseBinding
    {
        [ScenarioContext]
        public virtual ISharedContext Context { get; set; }

        [Then(@"I can read the property in a different step definition class")]
        public void ThenICanReadThePropertyInADifferentStepDefinitionClass()
        {
            Context.CustomerId.Should().Be(1234);
        }

    }

That code is now a test in the source code. If anyone has any suggestions about how the project can be improved let me know.

Advertisements