8

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

就我所见,这些属性总是在一个类中定义,其中包含在一些场景中使用的特定步骤。

他们可以去某个地方,以便适用于所有场景吗?或者是否将方法归因于[BeforeScenario][AfterScenario]导致它们在所有场景中运行,而不管它们实际放置在哪里?

4

3 回答 3

13

嗯...据我所知,根据文档,这些钩子始终是全局的,即来自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
  }
}

然后是测试规范

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

得到输出

I'm global
Given nothing
-> done: JustTheTest.GivenNothing() (0.0s)

所以看起来文档确实是正确的,您应该使用标记来控制BeforeScenario\AfterScenario是在您的场景之前还是之后运行。

这里还有一个很好的例子来说明标记是如何工作的 ->使用 SpecFlow 进行功能范围的步骤定义?

于 2013-10-29T07:38:01.807 回答
8

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

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

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

    [AfterScenario]
    public void AfterScenario()
    {
        // AfterScenario code
    }
}

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

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

[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();
    }
}

虽然这种方法不是全局的,但通过使所有 StepDefinition 都派生自 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 + "]");
    }
}

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

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]
于 2013-10-28T23:14:41.937 回答
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

在这里,您可以让“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
    } 

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

于 2013-10-29T07:49:07.710 回答