Наличие нескольких файлов шагов открывает несколько браузеров - PullRequest
2 голосов
/ 09 марта 2019

Проблема:

Если у меня более одного файла шагов, при выполнении тестов создается впечатление, что создание WebDriver для каждого происходит независимо от того, какие тесты я запускаю.

Я видел случайный браузер Chrome, открываемый всякий раз, когда я запускал свои тесты. В попытке выяснить, была ли какая-либо несовместимость между SpecFlow и ChromeDriver (я знаю, что это был долгий путь), я изменил WebDriver для своих поисковых тестов на Firefox и оставил WebDriver для моих тестов входа в систему как Chrome. Независимо от того, какие тесты я выполнял, я всегда видел 2 открытых браузера; один Chrome и один Firefox.

Когда я переместил все шаги из моего файла SearchTestSteps.cs в файл LoginTestSteps.cs, проблема исчезла.

Итак, да, это решает немедленную проблему, но неоптимально, чтобы все мои шаги были в одном файле. Это может быстро стать громоздким.

Поскольку каждый набор шагов должен иметь свой собственный WebDriver, я в растерянности.

Может быть, это как-то связано со структурой папок и где что-то хранится? Вот как выглядит моя.

Root
 |-Page Object Files
      |- Page Components
      |- Pages
      |- Test Tools  
 |- Step Definitions
      |- <*Steps.cs>  
 |- TESTS
      |- BDD Tests
          |-<*.feature>
      |- *standard selenium test files*

Код:

Login.feature
Feature: Login
    In order to be able to use Laserfiche
    As a legitimate user
    I want to be able to log into the repository

@SmokeTest
Scenario: Login with correct credentials
    Given I am on the Login page 
    And I have a good username/password combination
    And I select a repository
    When I fill out the form and submit
    Then I am taken to the repo page

---------------
LoginSteps.cs (I also have a SearchTestSteps.cs that looks very similar)
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using Selenium_C_Sharp_POC.Page_Object_Files.Pages;
using Selenium_C_Sharp_POC.Page_Object_Files.Test_Tools;
using TechTalk.SpecFlow;

namespace Selenium_C_Sharp_POC.StepDefinitions
{
    [Binding]
    public class LoginSteps
    {
        private static readonly IWebDriver Driver = new ChromeDriver();

        private static LoginPage _loginPage;
        private static string _username;
        private static string _password;
        private static string _repo;

        [AfterTestRun]
        public static void ShutDown()
        {
            Driver?.Close();
        }

        [Given(@"I am on the Login page")]
        public void GivenIAmOnTheLoginPage()
        {
            _loginPage = new LoginPage(Driver);
        }

        [Given(@"I have a good username/password combination")]
        public void GivenIHaveAGoodUsernamePasswordCombination()
        {
            _username = Nomenclature.WebClientPersonalUsername;
            _password = Nomenclature.WebClientPersonalPassword;
        }
        [Given(@"I select a repository")]
        public void GivenISelectARepository()
        {
            _repo = Nomenclature.RepoUnderTest;
        }

        [When(@"I fill out the form and submit")]
        public void WhenIFillOutTheFormAndSubmit()
        {
            _loginPage.Login(
                username: _username, 
                password: _password, 
                repo: _repo);
        }

        [Then(@"I am taken to the repo page")]
        public void ThenIAmTakenToTheRepoPage()
        {
            Assert.AreEqual(
                expected: _repo,
                actual: Driver.Title);

            HelperMethods.Logout(Driver);
        }
    }
}

Ответы [ 3 ]

1 голос
/ 09 марта 2019

Я понял, как решить эту проблему с помощью Binding Scopes.

В каждом из файлов Steps я могу сделать следующее:

  [BeforeFeature(), Scope(Feature = "SearchTests")]
  public static void Startup()
  {
      _driver = new ChromeDriver();
  }

  [AfterFeature()]
  public static void ShutDown()
  {
      _driver?.Close();
  }

При этом открывается и закрывается драйвер только для тестового файла, который я хочу. Я также могу выбрать область видимости тега перед каждым тестом, если мне нужно получить более детальную информацию.

0 голосов
/ 03 апреля 2019

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

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

Я считаю хорошей идеей реализовать «ленивый» веб-драйвер, поэтому окно браузера появляется только тогда, когда ваш код C # действительно должен взаимодействовать с ним. Этот класс LazyWebDriver реализует интерфейс IWebDriver и является оберткой для реального веб-драйвера.

LazyWebDriver.cs

public sealed class LazyWebDriver : IWebDriver
{
    private readonly Lazy<IWebDriver> driver;

    public string Title => driver.Value.Title;

    // Other properties defined in IWebDriver just pass through to driver.Value.Property

    public LazyWebDriver(Func<IWebDriver> driverFactory)
    {
        driver = new Lazy<IWebDriver>(driverFactory);
    }

    public IWebElement FindElement(By by)
    {
        return driver.Value.FindElement(by);
    }

    public void Close()
    {
        driver.Value.Close();
    }

    // other methods defined in IWebDriver just pass through to driver.Value.Method(...)
}

Затем, используя перехватчики SpecFlow (это просто фальшивка для «событий» в SpecFlow), вы можете создать свой настоящий веб-драйвер и ленивый веб-драйвер и зарегистрировать его в платформе SpecFlow:

SeleniumHooks.cs

[Binding]
public sealed class SeleniumHooks
{
    private readonly IObjectContainer objectContainer;

    public SeleniumHooks(IObjectContainer objectContainer)
    {
        this.objectContainer = objectContainer;
    }

    [BeforeFeature]
    public void RegisterWebDriver()
    {
        objectContainer.RegisterInstanceAs<IWebDriver>(new LazyWebDriver(CreateWebDriver));
    }

    private IWebDriver CreateWebDriver()
    {
        return new ChromeDriver();
    }

    [AfterFeature]
    public void DestroyWebDriver()
    {
        objectContainer.Resolve<IWebDriver>()?.Close();
    }
}

Наконец, несколько изменений в вашем файле LoginSteps.cs :

[Binding]
public class LoginSteps
{
    private readonly IWebDriver Driver;
    private LoginPage _loginPage;

    private static string _username;
    private static string _password;
    private static string _repo;

    public LoginSteps(IWebDriver driver)
    {
        Driver = driver;
    }

    [Given(@"I am on the Login page")]
    public void GivenIAmOnTheLoginPage()
    {
        _loginPage = new LoginPage(Driver);
    }

    [Given(@"I have a good username/password combination")]
    public void GivenIHaveAGoodUsernamePasswordCombination()
    {
        _username = Nomenclature.WebClientPersonalUsername;
        _password = Nomenclature.WebClientPersonalPassword;
    }
    [Given(@"I select a repository")]
    public void GivenISelectARepository()
    {
        _repo = Nomenclature.RepoUnderTest;
    }

    [When(@"I fill out the form and submit")]
    public void WhenIFillOutTheFormAndSubmit()
    {
        _loginPage.Login(
            username: _username, 
            password: _password, 
            repo: _repo);
    }

    [Then(@"I am taken to the repo page")]
    public void ThenIAmTakenToTheRepoPage()
    {
        Assert.AreEqual(
            expected: _repo,
            actual: Driver.Title);

        HelperMethods.Logout(Driver);
    }
}

Обратите внимание, что объект IWebDriver передается в качестве аргумента конструктора в LoginSteps. SpecFlow поставляется с интегрированной структурой внедрения зависимостей, которая достаточно умна, чтобы передавать LazyWebDriver, зарегистрированный в SeleniumHooks, в качестве аргумента IWebDriver в конструктор LoginSteps.

Обязательно сделайте поле _loginPage полем экземпляра, а не статическим.

0 голосов
/ 09 марта 2019

Возможно, вы создали экземпляр драйвера в каждом из файлов .cs. Например: в файле LoginSteps.cs вы создаете драйвер chrome в приведенной ниже папке.

private static readonly IWebDriver Driver = new ChromeDriver();

Вы должны создать драйвер вне файлов xStep.cs и просто передать его классу / методу, основанному на фреймворке.

...