How to properly manage and access webdriver instances to avoid problems with parallel execution of tests?

ⅰ亾dé卋堺 提交于 2019-12-24 00:38:04

问题


I've seen several approaches to instantiate web driver in Specflow examples.

  1. Creating it in the steps definition class and disposing it in Dispose method for the class

Why is it horrible? Cause 1 scenario doesn't equal 1 steps definition class as some steps are just shared between features and there will be more than 1 web driver instantiated. Example: https://www.softwaretestinghelp.com/specflow-and-selenium/

  1. Creating it in hooks [BeforeScenario] and destroying int in [AfterScenario]

It won't work with parallel execution(according to author). https://github.com/AutomateThePlanet/AutomateThePlanet-Learning-Series/tree/master/Specflow-Series/ExtendTestExecutionWorkflowUsingHooks

Question: How to manage WebDriver instances in Specflow UI tests solution with NUnit? Where and when initialize it, where and when destroy and how to access it in page object models and steps definition classes?


回答1:


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.



来源:https://stackoverflow.com/questions/58390535/how-to-properly-manage-and-access-webdriver-instances-to-avoid-problems-with-par

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