Reputation: 3087
I'm using context injection in SpecFlow but I've encountered an issue whereby I want to share a step bindings class, but I don't necessarily need to register all the constructor parameters.
I have various BeforeScenario hooks in a separate binding/hooks class where I register objects with the container, like below....
[Scope(Scenario = "Scenario A")]
[BeforeScenario(Order = 5)]
public void CreateApprenticeWithChecklist()
{
//Other stuff
_container.RegisterInstanceAs<Apprentice>(apprentice);
}
[Scope(Scenario = "Scenario B")]
[BeforeScenario(Order = 5)]
public void CreateApprenticeWithChecklistAllSignOff()
{
//Other stuff
_container.RegisterInstanceAs<Apprentice>(apprentice);
_container.RegisterInstanceAs<Dictionary<string, UserDetails>>(new Dictionary<string, UserDetails>
{
["Employer"] = employer.Key,
["Training Provider"] = trainingProvider.Key
});
}
I then have a step definitions class that both these scenarios will use....
[Binding]
public sealed class ApprenticeChecklistSteps
{
private Apprentice _apprentice;
private UserDetails _employer;
private UserDetails _trainingProvider;
public ApprenticeChecklistSteps(Apprentice apprentice, Dictionary<string, UserDetails> userDetails)
{
_apprentice = apprentice;
_employer = userDetails["Employer"];
_trainingProvider = userDetails["Training Provider"];
}
//etc
The problem is if I'm running Scenario A
there will be no registration for Dictionary<string, UserDetails> userDetails
and so I will get the Multiple public constructors with same maximum parameter count are not supported!
error.
How can I share step bindings between scenario's if I don't necessarily have or need a certain constructor parameter?
The only solutions I see are hacky
Create 'blank' registrations for all the unused constructor parameters so they are initialized
Or...
Create a separate POCO that contains all the possible registrations, and register whatever I need, when I need it
public class CheckListContext
{
public Apprentice Apprentice { get; set; }
public Dictionary<string, UserDetails> UserDetails { get; set; }
}
The registration in Scenario A BeforeScenario
step would then become...
_container.RegisterInstanceAs<CheckListContext>(new CheckListContext{Apprentice = apprentice});
Upvotes: 1
Views: 816
Reputation: 18783
It looks like you just want to share data between steps, not step bindings. The way to do this in SpecFlow is by using the scenario context to set data in one step and retrieve it in another step. For instance, I would have a step called Given an apprenticeship exists
. The step definition for this would be something like:
[Binding]
public class ApprenticeshipSteps
{
private readonly ScenarioContext scenario;
public ApprenticeshipSteps(ScenarioContext scenario)
{
this.scenario = scenario;
}
[Given(@"an apprenticeship exists")]
public void GivenAnApprenticeshipExists()
{
var apprenticeship = new Apprenticeship(...);
scenario["apprenticeship"] = apprenticeship;
// save to database if need be
}
}
[Binding]
public class MoreStepDefinitions
{
private readonly ScenarioContext scenario;
public MoreStepDefinitions(ScenarioContext scenario)
{
this.scenario = scenario;
}
[Then(@"a step that needs the apprenticeship")]
public void AnotherStep()
{
var apprenticeship = (Apprenticeship)scenario["apprenticeship"];
}
}
If need be you can put the apprenticeship Id in the scenario context instead if you need to get it from the database. The scenario context is basically just a bag of data passed around from step definition to step definition. This is the preferred way to share data between steps in SpecFlow.
Upvotes: 1