Reputation: 507
I want to have the following test step class structure:
[Binding]
public class BaseStep
{
[Given(@"there is a customer")]
public void GivenThereIsACustomer(Table table)
{
HandleCustomer(table);
}
protected virtual void HandleCustomer(Table table)
{
}
}
[Binding]
public class FeatureOneStep : BaseStep
{
protected override void HandleCustomer(Table table)
{
// feature one action
}
[Given(@"feature one specific step")]
public void GivenFeatureOneSpecificAction(Table table)
{
// do something
}
}
[Binding]
public class FeatureTwoStep : BaseStep
{
protected override void HandleCustomer(Table table)
{
// feature two action
}
[Given(@"feature two specific step")]
public void GivenFeatureTwoSpecificAction(Table table)
{
// do something
}
}
"Given there is a customer" is a common step that is used in both FeatureOne and FeatureTwo, but it will have different handling logic inside the two features. So I decide to put this step definition into a base class and override the protected methods in two derived classes respectively.
However, when I ran the tests, I have the following error:
TechTalk.SpecFlow.BindingException: Ambiguous step definitions found for step
'Given there is a customer':
CustomerTestBase.GivenThereIsACustomer(Table),
CustomerTestBase.GivenThereIsACustomer(Table)
Can any one tell me how to fix this issue?
Upvotes: 24
Views: 22925
Reputation: 1733
Specflow is a tool for handling the connection between the .feature file and the .cs file. This is not a tool to handle our abstractions. If we need any kind of abstractions or structure to prevent duplication or any other design problem, we can create it separately.
If you consider Specflow as a tool for binding, I am sure that you won't look for a way to handle your abstraction using it.
For example, define an abstract CustomerService
public abstract class CustomerService
{
public abstract void Handle();
}
Upvotes: 0
Reputation: 121
This worked well for me :
public class BaseSteps
{
[Given(@"Method called")]
public virtual void WhenMethodCalled()
{
}
}
[Binding]
[Scope(Feature= "specific_feature")
public class DerivedSteps : BaseSteps
{
[Given(@"Method called")]
[Scope(Feature= "specific_feature", Tag ="specific_tag")]
public override void WhenMethodCalled()
{
}
}
Upvotes: 12
Reputation: 461
Just figuring this out now myself, so a couple of notes (hopefully somebody can use this in the future):
Upvotes: 35
Reputation: 6961
The answer is simple; Don't use inheritance to define your bindings.
At run time SpecFlow finds its methods to call by scanning globally across all public classes looking for methods with matching [Given]
attributes. This means that you can't have two different implementations for the same Given there is a customer
statement, which if you think about it is quite a sensible design decision that will reduce ambiguity.
Upvotes: 13