如何正确管理和访问 webdriver 实例以避免并行执行测试的问题?
How to properly manage and access webdriver instances to avoid problems with parallel execution of tests?
我在 Specflow 示例中看到了几种实例化 Web 驱动程序的方法。
- 在步骤定义中创建它 class 并在 class
的 Dispose
方法中处理它
为什么可怕?原因 1 个场景不等于 1 个步骤定义 class,因为某些步骤仅在功能之间共享,并且将实例化 1 个以上的 Web 驱动程序。示例:https://www.softwaretestinghelp.com/specflow-and-selenium/
- 在钩子中创建它
[BeforeScenario]
并在 [AfterScenario]
中销毁 int
它不适用于并行执行(根据作者的说法)。 https://github.com/AutomateThePlanet/AutomateThePlanet-Learning-Series/tree/master/Specflow-Series/ExtendTestExecutionWorkflowUsingHooks
问题:如何使用 NUnit 管理 Specflow UI 测试解决方案中的 WebDriver
个实例?何时何地初始化它,何时何地销毁它以及如何在页面对象模型和步骤定义中访问它 classes?
您需要使用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 项目中,Web 驱动程序对象被初始化为静态 属性。这就是该代码示例不能用于并行测试的原因。听起来所有执行场景都使用相同的 AppDomain,因此它们共享静态 class 状态,这意味着每个场景都试图使用相同的浏览器实例。
我在 Specflow 示例中看到了几种实例化 Web 驱动程序的方法。
- 在步骤定义中创建它 class 并在 class 的
Dispose
方法中处理它
为什么可怕?原因 1 个场景不等于 1 个步骤定义 class,因为某些步骤仅在功能之间共享,并且将实例化 1 个以上的 Web 驱动程序。示例:https://www.softwaretestinghelp.com/specflow-and-selenium/
- 在钩子中创建它
[BeforeScenario]
并在[AfterScenario]
中销毁 int
它不适用于并行执行(根据作者的说法)。 https://github.com/AutomateThePlanet/AutomateThePlanet-Learning-Series/tree/master/Specflow-Series/ExtendTestExecutionWorkflowUsingHooks
问题:如何使用 NUnit 管理 Specflow UI 测试解决方案中的 WebDriver
个实例?何时何地初始化它,何时何地销毁它以及如何在页面对象模型和步骤定义中访问它 classes?
您需要使用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 项目中,Web 驱动程序对象被初始化为静态 属性。这就是该代码示例不能用于并行测试的原因。听起来所有执行场景都使用相同的 AppDomain,因此它们共享静态 class 状态,这意味着每个场景都试图使用相同的浏览器实例。