全局[BeforeScenario],[AfterScenario]在SpecFlow中执行

lar*_*ryq 7 specflow

我们正在尝试在我们的specflow测试中实现全局挂钩,并且不完全确定方法[BeforeScenario][AfterScenario]属性如何工作.

我看到它完成的方式,这些属性总是在包含几个场景中使用的特定步骤的类中定义.

他们可以去某个地方,以便适用于所有场景吗?或者根本归因与方法[BeforeScenario],并[AfterScenario]导致他们对所有情景下运行,无论在哪里,他们实际上是放在哪里?

AlS*_*Ski 12

嗯......据我所知,根据文档,这些钩子总是全球性的,即来自http://www.specflow.org/documentation/hooks/

钩子(事件绑定)可用于在特定事件上执行其他自动化逻辑,例如在执行场景之前.

挂钩是全局的,但可以限制为仅针对具有特定标记的功能或方案运行(请参见下文).未定义同一事件的挂钩的执行顺序.

事实上,通过以下方式生成一个小型演示项目

[Binding]
public class Unrelated
{
  [BeforeScenario]
  public void WillBeCalledIfGlobal()
  {
    Console.WriteLine("I'm global");
  }
}

[Binding]
public class JustTheTest
{
  [Given("nothing")]
  public void GivenNothing()
  {
     // Don't do anything
  }
}
Run Code Online (Sandbox Code Playgroud)

然后是测试规范

As a developer
In order to understand how BeforeSpecifcation works
I want to know what the following does

Scenario: See if BeforeSpecifcation hook gets called
Given nothing
Run Code Online (Sandbox Code Playgroud)

得到输出

I'm global
Given nothing
-> done: JustTheTest.GivenNothing() (0.0s)
Run Code Online (Sandbox Code Playgroud)

所以它确实看起来好像文档是正确的,你应该使用标记来控制是否在你的场景之前或之后运行BeforeScenario\ AfterScenario.

还有一个关于标记如何在这里工作的好例子 - > 使用SpecFlow进行特征范围的步骤定义?


Ben*_*ith 8

是的,您可以创建全局的BeforeScenario和AfterScenario方法,但实际上我发现这是不可取的,因为通常相同的前后步骤不适用于测试项目中的所有步骤.

相反,我为我的步骤定义创建了一个基类,它将具有我想应用于所有场景的BeforeScenario和AfterScenarios方法,例如

public class BaseStepDefinitions
{
    [BeforeScenario]
    public void BeforeScenario()
    {
        // BeforeScenario code
    }

    [AfterScenario]
    public void AfterScenario()
    {
        // AfterScenario code
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我没有在此类上使用Binding属性.如果确实包含它,那么BeforeScenario和AfterScenario步骤将是全局的.

然后我从这个基本步骤定义类派生我的步骤定义类,以便它们将具有Before和After场景方法,例如

[Binding]
public class SpecFlowFeature1Steps : BaseStepDefinitions
{
    [Given(@"I have entered (.*) into the calculator")]
    public void GivenIHaveEnteredIntoTheCalculator(int inputValue)
    {
        ScenarioContext.Current.Pending();
    }

    [When(@"I press add")]
    public void WhenIPressAdd()
    {
        ScenarioContext.Current.Pending();
    }

    [Then(@"the result should be (.*) on the screen")]
    public void ThenTheResultShouldBeOnTheScreen(int expectedResult)
    {
        ScenarioContext.Current.Pending();
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然这种方法不是全局的,但通过使所有StepDefinitions派生自BaseStepDefinition类,我们可以获得相同的结果.

它还提供更多控制,即如果您不想要BeforeScenario或AfterScenario绑定,则不要从基本步骤派生.


对不起,这不起作用.一旦开始使用多个Binding类,最终会有多个调用.例如,如果我扩展上面的示例将绑定拆分为三个类,

[Binding]
public class SpecFlowFeature1Steps : BaseStepDefinitions
{
    [Given(@"I have entered (.*) into the calculator")]
    public void GivenIHaveEnteredIntoTheCalculator(int inputValue)
    {
        //ScenarioContext.Current.Pending();
    }
}

[Binding]
public class SpecFlowFeature2Steps : BaseStepDefinitions
{
    [When(@"I press add")]
    public void WhenIPressAdd()
    {
        //ScenarioContext.Current.Pending();
    }
}

[Binding]
public class SpecFlowFeature3Steps : BaseStepDefinitions
{
    [Then(@"the result should be (.*) on the screen")]
    public void ThenTheResultShouldBeOnTheScreen(int expectedResult)
    {
        //ScenarioContext.Current.Pending();
    }
}

public class BaseStepDefinitions
{
    [BeforeScenario]
    public void BeforeScenario()
    {
        // BeforeScenario code
        Console.WriteLine("Before. [Called from "+ this.GetType().Name+"]");
    }

    [AfterScenario]
    public void AfterScenario()
    {
        // AfterScenario code
        Console.WriteLine("After. [Called from " + this.GetType().Name + "]");
    }
}
Run Code Online (Sandbox Code Playgroud)

然后当我运行它时,输出是

Before. [Called from SpecFlowFeature1Steps]
Before. [Called from SpecFlowFeature2Steps]
Before. [Called from SpecFlowFeature3Steps]
Given I have entered 50 into the calculator
-> done: SpecFlowFeature1Steps.GivenIHaveEnteredIntoTheCalculator(50) (0.0s)
And I have entered 70 into the calculator
-> done: SpecFlowFeature1Steps.GivenIHaveEnteredIntoTheCalculator(70) (0.0s)
When I press add
-> done: SpecFlowFeature2Steps.WhenIPressAdd() (0.0s)
Then the result should be 120 on the screen
-> done: SpecFlowFeature3Steps.ThenTheResultShouldBeOnTheScreen(120) (0.0s)
After. [Called from SpecFlowFeature1Steps]
After. [Called from SpecFlowFeature2Steps]
After. [Called from SpecFlowFeature3Steps]
Run Code Online (Sandbox Code Playgroud)


Tim*_*den 6

为了控制“BeforeScenario”和“AfterScenario”,您可以使用标签。这使您可以控制哪些场景应该在块之前和之后运行。您的场景如下所示:

@GoogleChrome
Scenario: Clicking on a button
    Given the user is on some page
    When the user clicks a button
    Then something should happen
Run Code Online (Sandbox Code Playgroud)

在这里,您可以让“BeforeScenario”在 Google Chrome 中为您启动浏览器会话,并为不同的浏览器实现类似的标签。你的“BeforeScenario”看起来像这样:

[Binding]
class Browser
{         
    [BeforeScenario("GoogleChrome")]
    public static void BeforeChromeScenario()
    {
        // Start Browser session and do stuff
    }

    [AfterScenario("GoogleChrome")]
    public static void AfterChromeScenario()
    {
        // Close the scenario properly
    } 
Run Code Online (Sandbox Code Playgroud)

我认为使用标签是保持场景干净的好方法,并为您提供额外的功能,让您控制每个场景应该做什么。