Как правильно управлять экземплярами веб-драйвера и получать к ним доступ, чтобы избежать проблем с параллельным выполнением тестов? - PullRequest
2 голосов
/ 15 октября 2019

Я видел несколько подходов к созданию экземпляра веб-драйвера в примерах Specflow.

  1. Создание его в классе определения шагов и размещение его в методе Dispose для класса

Почему это ужасно? Причина 1 сценарий не равен классу определения 1 шага, так как некоторые шаги просто разделены между функциями, и будет реализовано более 1 веб-драйвера. Пример: https://www.softwaretestinghelp.com/specflow-and-selenium/

Создание его в хуках [BeforeScenario] и уничтожение int в [AfterScenario]

Не будет работать при параллельном выполнении (по мнению автора). https://github.com/AutomateThePlanet/AutomateThePlanet-Learning-Series/tree/master/Specflow-Series/ExtendTestExecutionWorkflowUsingHooks

Вопрос: Как управлять WebDriver экземплярами в решении тестов пользовательского интерфейса Specflow с помощью NUnit? Где и когда его инициализировать, где и когда уничтожить и как получить к нему доступ в объектных моделях страниц и классах определения шагов?

1 Ответ

2 голосов
/ 15 октября 2019

Вам необходимо использовать инфраструктуру внедрения зависимостей, которая поставляется с SpecFlow. Вариант № 2, где вы создаете его в [BeforeScenario] и уничтожаете его в [AfterScenario], является правильным способом, но тогда вам нужно зарегистрировать объект IWebDriver в каркасе внедрения зависимостей:

[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();
        }
    }
}

Ваши определения шагов должны принимать объект IWebDriver в качестве аргумента конструктора. Вы даже можете зарегистрировать объекты вашей страницы в DI-фреймворке.

[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");
    }
}

В проекте GitHub, на который вы ссылались, объект веб-драйвера инициализируется как статическое свойство. Именно поэтому этот пример кода нельзя использовать для параллельных тестов. Похоже, что все выполняющиеся сценарии используют один и тот же домен приложения, поэтому они разделяют статическое состояние класса, что означает, что каждый сценарий пытается использовать один и тот же экземпляр браузера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...