具有相同步骤的Specflow Feature文件导致多个浏览器实例启动

我在我的C#Specflow测试项目中至少有3个.feature文件,例如:

Given I am at the Home Page

当我第一次在文件Feateure1.feature编写步骤并创建了step方法时,我将它放在一个step文件中,比如, Steps1.cs ,它inheritance自初始化FirefoxDriver的基类。 我的所有StepsXXXX.cs类都inheritance自这个基类。

然后,我写了Feature2.feature ,它也有一个步骤Given I am at the Home Page 。 并且步骤自动绑定到Steps1.cs中的Steps1.cs

“直到现在,没问题。 这就是我想要的 – 在整个测试项目中都有可重复使用的步骤。 但问题是,每当我运行一个具有不同StepsXXXX文件步骤的场景时,我就会运行各种浏览器实例。

======

我很确定这是因为我的StepsXXXX (绑定类)都inheritance自这个具有自己的IWebDriver的基类,并且当调用该步骤时,其他所有内容(包括之前/之后的场景方法)叫做。 但我无法弄清楚如何解决这个问题。

我仍然想要可重复使用的步骤。 我试图将这些步骤放在基类中,但它没有用。 我也想过改变绑定,但是specflow使用有意义的字符串来做,我不想把它们改成误导性的字符串。

有没有人偶然发现了这个? 任何帮助都非常感谢。

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

因此,您的简单案例都保留在Steps1类中,因为它是第一个完美匹配。 你的更复杂的情况开始实例化更多的类,因此多个浏览器,你的重构尝试将无法工作,因为你的抽象基类没有[绑定]。

我可能首先将所有步骤类层次结构扁平化为一个大的AllSteps.cs类。 这看起来可能适得其反,但您所做的只是安排代码,了解当前绑定对SpecFlowfunction的影响。 这样您就可以开始重构不同GWT绑定之间的重叠。

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

您可以使用[Scope(Tag = "mytag", Feature = "feature title", Scenario = "scenario title")]使用Scoped绑定来引用特定场景或这样的假设:

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

我面临同样的问题。

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

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

对两个步骤类使用[BeforeScenario][AfterScenario]也会使运行器在两个类中运行before和after方法,使其设置运行两次。

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

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

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

我认为这比问题和答案要简单得多。 这里有两个问题:

AISki在关于specflow上下文的文档链接中给出了正确的答案,但它并没有真正作为答案呈现,并且在提出一个较差的答案作为实际答案时分散注意力。

关于你看到的行为的答案是,你应该准确地期望你设置的方式发生了什么。 如果你有多个创建浏览器实例的绑定类(如果它们都有一个创建浏览器实例的公共基础),并且它们在你的function中有匹配,你应该期望多个浏览器实例。

您想要的答案(单个浏览器在您的步骤中共享)是您应该使用specflow的上下文function来控制对浏览器实例的依赖性。 这相当于dependency injection。 你的步骤定义类应该对构建浏览器实例的东西采取构造函数依赖 – specflow为你管理依赖关系,你将为你创建的第一个类获得一个新实例,然后在之后获得相同的实例。

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