Specflow Feature files with same steps causing multiple browser instances to launch

僤鯓⒐⒋嵵緔 提交于 2019-12-03 07:55:22

The problem is that SpecFlow bindings don't respect inheritance. All custom attributes are considered global, and so all SpecFlow does is search for a list of classes with a [Binding]then build up a dictionary for all the [Given]/[When]/[Then]s so that it can evaluate them for a best match. It will then create an instance of the class (if it hasn't already done so) and call the method on it.

As a result your simple cases all stay in the Steps1 class, because its the first perfect match. Your more complicated cases start instantiating more classes, hence multiple browsers, And your attempt to refactor won't work because your abstract base class doesn't have a [Binding] on it.

I'd probably start by flattening all your step class hierarchy, into one big AllSteps.cs class. This may seem counter-productive, but all you are really doing is arranging the code just how the current bindings appear to your SpecFlow features. This way you can start to refactor out the overlaps between the different GWT bindings.

At the moment your bindings are arranged around the scenarios. What you will need to do is refactor them around your functionality. Have a read of Whose Domain is it anyway? before you start and this will probably give you some good ideas. Then have a look at Sharing-Data-between-Bindings on the SpecFlow documentation to work out how to link between your new steps classes.

You can use Scoped bindings using [Scope(Tag = "mytag", Feature = "feature title", Scenario = "scenario title")] to referred on specific scenario or feateure like this:

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

}

I facing the same issue.

I wanted to have one feature file that will call steps in different cs classes. The issue came across when I want to setup and tear down for each scenario.

Using step class constructor and Dispose() not possible because the scenario uses more than one step class which I don't want to 'setup' multiple time in a scenario.

Using [BeforeScenario] and [AfterScenario] for both step classes also makes the runner run the before and after methods in both class that makes it setup run twice.

So what I was done is create another third class called something like BrowserScenarioSetup put the before and after scenario class in it to setup a browser for the scenario and assign to ScenarioContext.Current dictionary. When the test run, only one browser created for a scenario and I can use scenario steps defined in any class but just uses Scenario.Context.Current to get the browser instance.

I can make both step classes have a base step class and create a short method to get browser instance (or any shared instance created in setup) just to hide Scenario.Context.Current

Finally I can mark [BeforeScenario("Browser", "IE")] and use @Browser and @IE in a feature or scenario to only call this setup method in suitable context.

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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!