10

I have at least 3 .feature files in my C# Specflow tests project in which I have the step, for instance:

Given I am at the Home Page

When I first wrote the step in the file Feateure1.feature and created the step method, I placed it in a step file, let's say, Steps1.cs, which inherits from a base class that initializes a FirefoxDriver. All my StepsXXXX.cs classes inherit from this base class.

Then, I wrote Feature2.feature, which also has a step Given I am at the Home Page. And the step was automaticaly bound to the one in Steps1.cs

'Till now, no problem. That's pretty much what I wanted - to have reusable steps throughout the test project. But the problem is, whenever I'm running a scenario that has steps in diferent StepsXXXX files, I get various browser instances running.

======

I'm pretty sure this is due to the fact that My StepsXXXX (binding classes) all inherit from this base class that has a IWebDriver of its own, and when the step is called, everything else (including the before/after scenario methods) is called. But I can't figure out how to work around this.

I still want reusable steps. I tried to put these steps in the base class, but it did not work. I thought of changing the bindings too, but specflow uses meaningfull strings to do so, and I don't want to change them to misleading strings.

Has anyone stumbled across this? Any help is really appreciated.

4

4 回答 4

6

问题是 SpecFlow 绑定不尊重继承。所有自定义属性都被认为是全局的,因此 SpecFlow 所做的只是搜索具有 [Binding] 的类列表,然后为所有 [Given]/[When]/[Then] 构建一个字典,以便它可以评估它们为最佳匹配。然后它会创建一个类的实例(如果它还没有这样做的话)并调用它的方法。

结果,您的简单案例都保留在 Steps1 类中,因为它是第一个完美匹配。您更复杂的案例开始实例化更多类,因此需要多个浏览器,并且您的重构尝试将不起作用,因为您的抽象基类上没有 [Binding]。

我可能会首先将所有步骤类层次结构扁平化为一个大的 AllSteps.cs 类。这看起来可能会适得其反,但您真正要做的只是安排代码,以使当前绑定显示在您的 SpecFlow 功能中。通过这种方式,您可以开始重构不同 GWT 绑定之间的重叠。

目前,您的绑定是围绕场景安排的。您需要做的是围绕您的功能重构它们。无论如何阅读谁的域?在你开始之前,这可能会给你一些好主意。然后查看 SpecFlow 文档中的Sharing-Data-between-Bindings以了解如何在新步骤类之间进行链接。

于 2013-03-19T18:50:34.927 回答
6

您可以使用在特定场景或功能上引用的Scoped 绑定,如下所示:[Scope(Tag = "mytag", Feature = "feature title", Scenario = "scenario title")]

Feature: Feateure1

Scenario: demo
Given I am at the Home Page
When ....

[Binding, Scope(Feature = "Feateure1")]
public class Steps1{

 [Given(@"Given I am at the Home Page")]
 public void GivenIAmAtTheHomePage(){
  {  }
}

Feature: Feateure2

Scenario: demo
Given I am at the Home Page
When ....
...

[Binding,Scope(Feature = "Feateure2")]
public class Steps2{

 [Given(@"Given I am at the Home Page")]
 public void GivenIAmAtTheHomePage(){
 {  }

}
于 2016-06-28T08:46:12.913 回答
4

i think this is a lot more simple than the question and answers here make it out to be. there are really two questions at play here:

AISki gave you the right answer in the link to documentation about specflow context, but it was not really presented as the answer and there was distraction in presenting an inferior answer as the actual answer.

the answer as to the behavior you see is that you should expect exactly what is happening with the way you set things up. if you have multiple binding classes that create browser instances (and you do if they all have a common base that creates a browser instance) and they have matches in your features, you should expect multiple browser instances.

The answer for what you intend (a single browser shared among your steps) is that you should use the context feature of specflow to control the dependency on a browser instance. this amounts to dependency injection. your step definition classes should take a constructor dependency on something that creates your browser instance - specflow manages dependencies for you and you'll get a new instance for the first of your classes created and then the same one after that.

https://github.com/techtalk/SpecFlow/wiki/Sharing-Data-between-Bindings

于 2014-03-18T10:57:25.063 回答
3

我面临同样的问题。

我想拥有一个功能文件,它将调用不同 cs 类中的步骤。当我想为每个场景设置和拆除时遇到了这个问题。

使用步骤类构造函数并且Dispose()不可能,因为该场景使用了多个步骤类,我不想在一个场景中多次“设置”。

对两个 step 类使用[BeforeScenario]and[AfterScenario]也会使运行器在两个类中运行 before 和 after 方法,这使得 setup 运行两次。

所以我所做的是创建另一个第三类,称为BrowserScenarioSetup将之前和之后的场景类放入其中,为场景设置浏览器并分配给ScenarioContext.Current字典。测试运行时,只为一个场景创建了一个浏览器,我可以使用任何类中定义的场景步骤,但仅用于Scenario.Context.Current获取浏览器实例。

我可以让两个步骤类都有一个基本步骤类并创建一个简短的方法来获取浏览器实例(或在设置中创建的任何共享实例)只是为了隐藏Scenario.Context.Current

最后,我可以[BeforeScenario("Browser", "IE")]在功能或场景中标记和使用@Browser 和@IE,以便仅在合适的上下文中调用此设置方法。

于 2013-08-01T16:27:01.077 回答