You need to use the dependency injection framework that comes with SpecFlow. Option #2 where you create it in the [BeforeScenario]
and destroy it in the [AfterScenario]
is the right way to do, but then you need to register the IWebDriver
object with the dependency injection framework:
[Binding]
public class WebDriverHooks
{
private readonly IObjectContainer container;
public WebDriverHooks(IObjectContainer container)
{
this.container = container;
}
[BeforeScenario]
public void CreateWebDriver()
{
FirefoxDriver driver = new FirefoxDriver();
// Make 'driver' available for DI
container.RegisterInstanceAs<IWebDriver>(driver);
}
[AfterScenario]
public void DestroyWebDriver()
{
var driver = container.Resolve<IWebDriver>();
if (driver != null)
{
driver.Quit();
driver.Dispose();
}
}
}
Your step definitions need to accept an IWebDriver object as a constructor argument. You could even register your page objects with the DI framework too.
[Binding]
public class LoginSteps
{
private readonly IWebDriver driver;
private readonly LoginPage loginPage;
public LoginSteps(IWebDriver driver)
{
// Assign 'driver' to private field or use it to initialize a page object
this.driver = driver;
// Initialize Selenium page object
this.loginPage = new LoginPage(driver);
}
[When(@"I go to the login page")]
public void WhenIGoToTheLoginPage()
{
// Use 'driver' in step definition
driver.FindElement(By.LinkText("Sign In")).Click();
}
[When(@"I log in")]
public void WhenILogIn()
{
// Use Selenium page object in step definition
loginPage.LogIn("testUser", "testPassword");
}
}
In the GitHub project you referenced, the web driver object is initialized in as a static property. This is the reason why that code example cannot be used for parallel tests. It sounds like all executing scenarios are using the same AppDomain, so they share static class state, which means each scenario is attempting to use the same browser instance.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…