【问题标题】:Specflow test step inheritance causes "Ambiguous step definitions"Specflow 测试步骤继承导致“不明确的步骤定义”
【发布时间】:2014-10-15 11:34:26
【问题描述】:

我希望有以下测试步骤类结构:

[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
    }
}

“假设有客户”是 FeatureOne 和 FeatureTwo 都使用的常用步骤,但在这两个功能中会有不同的处理逻辑。所以我决定把这个步骤定义放到一个基类中,分别覆盖两个派生类中的protected方法。

但是,当我运行测试时,出现以下错误:

TechTalk.SpecFlow.BindingException: Ambiguous step definitions found for step
'Given there is a customer': 
CustomerTestBase.GivenThereIsACustomer(Table),   
CustomerTestBase.GivenThereIsACustomer(Table)

谁能告诉我如何解决这个问题?

【问题讨论】:

    标签: c# inheritance specflow acceptance-testing ambiguous


    【解决方案1】:

    答案很简单;不要使用继承来定义绑定。

    在运行时,SpecFlow 通过全局扫描所有公共类来查找要调用的方法,以寻找具有匹配[Given] 属性的方法。这意味着您不能对同一个 Given there is a customer 语句有两个不同的实现,如果您考虑一下,这是一个非常明智的设计决策,可以减少歧义。

    【讨论】:

    • 他是对的。仅当您控制初始化时,继承才有效。由于测试是自动生成的,因此您无法定义将使用哪个具体类。
    • 如果您坚持使用继承,您可以编写一个构建步骤,然后调用子类。 1 - BaseClass bc = FeatureOneClass();和 2 - bc.featureonestep;
    • 如果基类是抽象的,我相信这个推理不适用。 SpecFlow应该只对具体的类感兴趣,但它似乎扫描得太松散了。
    【解决方案2】:

    我自己现在才弄清楚,所以有几点说明(希望将来有人可以使用它):

    • 不要在基类中包含 [Binding] 属性
    • 为每个功能文件创建一个派生类
      • 将 [Binding] 属性添加到派生类(将自动包含基类中的所有步骤定义)
      • 为派生类添加[Scope]属性;为命名参数Feature指定特征的名称

    【讨论】:

    • 这是正确的答案。我知道 SpecFlow 不希望我们使用继承,但在我看来这是一个不必要的混乱设计选择。面向对象的编程技术已经提供了强大的代码重用方法。为什么要重新发明轮子?
    【解决方案3】:

    这对我很有效:

    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()
        {
    
        }
    }
    

    【讨论】:

    • 成功了!这是@RunOfTheShipe 答案的编码示例
    猜你喜欢
    • 1970-01-01
    • 2011-07-16
    • 1970-01-01
    • 2014-09-26
    • 1970-01-01
    • 2020-12-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多