在 SpecFlow 中,我应该为正在测试的对象使用 class 字段还是 ScenarioContext?

In SpecFlow, should I use a class field or ScenarioContext for the object that I'm testing?

我正在使用 SpecFlow 测试 class MortgageCalculator。我发现我有两种设置步骤文件的方法,一种是使用 class 级别的 MortgageCalculator,另一种是使用 ScenarioContext(见下文)。哪个更好?

我发现选项 1 更容易,因为我不必一直获取和设置 ScenarioContext。但我被教导使用 ScenarioContext。

选项 1:

[Binding]
public sealed class MortgageCalculatorSteps
{
    private MortgageCalculator calculator;

    [Given(@"I have a MortgageCalculator")]
    public void GivenIHaveAMortgageCalculator()
    {
        calculator = new MortgageCalculator();
    }

    [Then(@"I can do something with the calculator")]
    public void ThenICanDoSomethingWithTheCalculator()
    {
        calculator.DoSomething();
    }
}

选项 2:

[Binding]
public sealed class MortgageCalculatorSteps
{
    [Given(@"I have a MortgageCalculator")]
    public void GivenIHaveAMortgageCalculator()
    {
        var calculator = new MortgageCalculator();
        ScenarioContext.Current.Set(calculator);
    }

    [Then(@"I can do something with the calculator")]
    public void ThenICanDoSomethingWithTheCalculator()
    {
        var calculator = ScenarioContext.Current.Get<MortgageCalcualtor>();
        calculator.DoSomething();
    }
}

SpecFlow 有一个名为上下文注入的概念。
这是在场景测试 运行 期间存储状态的首选方式。
在此处查看文档:http://www.specflow.org/documentation/Context-Injection/

在我看来,您列出的两个选项都不是最佳解决方案。正如 Andreas 在另一个答案中指出的那样,最好的选择是使用 ContextInjection。为什么?

  • 当测试运行并行时有效,使用ScenarioContext.Current不会
  • 允许在包含步骤的不同 类 之间共享数据,这反过来又允许您以任何您想要的方式组织步骤并避免包含许多步骤方法的非常大的 类
  • 允许您的数据是强类型的
  • 允许以适当的内聚方式收集您的数据 类,每个数据都保持单一职责原则

我们倾向于将这些称为 类 上下文,因此在您的情况下我的选择是这样做,可能是:

[Binding]
public sealed class MortgageCalculatorSteps
{
    private MortgageCalculatorContext calculatorContext;

    public MortgageCalculatorSteps(MortgageCalculatorContext calculatorContext)
    {
        this.calculatorContext=calculatorContext;
    }

    [Given(@"I have a MortgageCalculator")]
    public void GivenIHaveAMortgageCalculator()
    {
        calculatorContext.Calculator = new MortgageCalculator();
        // or you could do something like: calculator.InitialiseCalculator()
    }

    [Then(@"I can do something with the calculator")]
    public void ThenICanDoSomethingWithTheCalculator()
    {
        calculatorContext.Calculator.DoSomething();
    }
}

在这样一个简单的例子中,好处可能并不明显,但根据我的经验,从长远来看,这会让你的生活变得更简单 运行。