В конечном итоге это вызвано созданием веб-драйверов в качестве статических полей в ваших классах определения шагов. Вам нужно централизовать эту логику.
Вы хотите создать свой веб-драйвер перед функцией, зарегистрировать его в контейнере внедрения зависимостей 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
полем экземпляра, а не статическим.