Reputation: 111
I've read that using inheritance is not possible when using Specflow, which makes sense most of the time. However, I've run across a situation that seems to require the proper the use of inheritance. Here are my classes:
Base Class:
public class StepBaseClass
{
protected readonly ScenarioContext scenarioContext;
public StepBaseClass(ScenarioContext scenarioContext)
{
this.scenarioContext = scenarioContext;
}
}
First Inherited Class:
[Binding]
public class StudioEnterpriseImportConnectorSteps:StepBaseClass
{
public StudioEnterpriseImportConnectorSteps(ScenarioContext scenarioContext) :base(scenarioContext)
{
}
[Given(@"I have a data record that I want to send to the import service")]
public void GivenIHaveADataRecordThatIWantToSendToTheImportService()
{
scenarioContext.Pending();
}
[When(@"I send the information to an invalid URL")]
public void WhenISendTheInformationToAnInvalidURL()
{
scenarioContext.Pending();
}
[Then(@"an error should be generated")]
public void ThenAnErrorShouldBeGenerated()
{
scenarioContext.Pending();
}
}
2nd inherited class:
[Binding]
public class SitemapSteps:StepBaseClass
{
public SitemapSteps(ScenarioContext scenarioContext):base(scenarioContext)
{
}
[When(@"I visit the URL (.*)")]
public void WhenIVisitTheSitemapURL(string URL)
{
scenarioContext.Add("result", TestUtilities.GetResponseCode(URL));
scenarioContext.Add("response", TestUtilities.GetResponseBody(URL));
}
[Then(@"the response code should be (.*)")]
public void ThenTheResponseCodeShouldBe(string responseCode)
{
HttpStatusCode result = scenarioContext.Get<HttpStatusCode>("result");
Assert.Equal(responseCode, result.ToString());
}
}
As you can see, the only thing that I'm inheriting the the scenarioContext
, which is something that I need to do in order to write multi-threaded tests. So instead of repeating this piece of code for each of my classes, I would like to be able to inherit from a base class. What is the proper method of initializing that variable so that I can use it in each of my derived classes?
Upvotes: 1
Views: 859
Reputation: 5825
The proper way depends as always on your individual situaion. I recommend always to not use base classes and use context injection everywhere. The small number of code that is repeated in the constructor is a small price for a good separation and splitting of your bindings and their implementation.
To get more info about this topic, Gaspar Nagy wrote a nice blog article about the pros and cons of step base classes in SpecFlow: http://gasparnagy.com/2017/02/specflow-tips-baseclass-or-context-injection/
Upvotes: 1
Reputation: 5688
After initializing my Dependency Injection in the Specflow Test hooks, I would have a class called ApplicationContext
with a static resolve method which would return me my ScenarioContext
instance like so:
public class ApplicationContext
{
public static T Resolve<T>() where T: class
{
return container.GetInstance<T>();
}
}
Then in my steps class, I would resolve the ScenarioContext
like this:
scenarioContext = (ScenarioContext)ApplicationContext.Resolve<IScenarioContext>();
Upvotes: 0