我们最近开始使用WebDriver(支持Selenium 1)使用NUnit框架执行浏览器测试。由于我们希望在各种浏览器中运行测试,因此我们为每个浏览器定义驱动程序,并在夹具设置期间将它们放入列表中:
[TestFixtureSetUp]
public void SetupTest()
{
// Load drivers
Drivers = new List<IWebDriver>
{
new ChromeDriver(),
...
};
在每一个测试中,我们都会像这样遍历列表:
[Test]
public void SomeTest()
{
foreach (var driver in Drivers)
{
driver.Navigate().GoToUrl("...");
...
在所有测试方法中都这样做是错误的。测试方法不应该关注他们应该使用什么驱动程序。理想情况下,我们会这样:
public void SomeTest(IWebDriver driver)
{
driver.Navigate().GoToUrl("...");
...
我们可以解决这个问题的一种方法是使用TestCases:
[TestCase(new ChromeDriver())]
[TestCase(new FireFoxDriver())]
...
但这有很多重复,并将驱动程序正确初始化的问题转移到每个测试的属性中。不是真正的收获。
有没有办法告诉NUnit框架执行整套测试并在每次运行中为各个测试注入不同的参数?或者还有其他任何好的解决方案吗?
答案 0 :(得分:4)
您应该可以使用TestCaseSourceAttribute。首先创建一个通常可访问的类,它提供了Web驱动程序的集合:
public static class WebDriverFactory
{
public static IWebDriver[] Drivers =
{
new ChromeDriver(),
new FirefoxDriver(),
...
};
}
接下来,实现依赖于Web驱动程序的单元测试:
[Test, TestCaseSource(typeof(WebDriverFactory), "Drivers")]
public void SomeTest(IWebDriver driver)
{
driver.Navigate().GoToUrl("...");
...
}
(可选)要在实现每个单元测试时减少键入,还要定义一个新的 Attribute 类,该类继承自TestCaseSourceAttribute
并且只实现默认构造函数:
public class WebDriverSourceAttribute : TestCaseSourceAttribute
{
public WebDriverSourceAttribute() : base(typeof(WebDriverFactory), "Drivers")
{
}
}
使用继承的WedDriverSource
属性,单元测试现在可以简化为:
[Test, WebDriverSource]
public void SomeTest(IWebDriver driver)
{
driver.Navigate().GoToUrl("...");
...
}
答案 1 :(得分:3)
没有“最佳”的方法,但我完成此任务的方式如下:
我创建了一个枚举:
/// <summary>
/// Enum that holds references to different browsers used in testing.
/// </summary>
public enum BrowserTypeEnum
{
/// <summary>
/// Google Chrome.
/// </summary>
Chrome,
/// <summary>
/// Mozilla Firefox.
/// </summary>
Firefox,
/// <summary>
/// Internet Explorer.
/// </summary>
InternetExplorer
}
在TestFixture中调用它,如下所示:
/// <summary>
/// Tests related to browsing Google
/// </summary>
[TestFixture(BrowserTypeEnum.Chrome)]
[TestFixture(BrowserTypeEnum.Firefox)]
public class GoogleTests : AbstractTestFixture
{
}
在AbstractTestFixture中:
/// <summary>
/// Create's the browser used for this test fixture.
/// <para>
/// Must always be called as part of the test fixture set up.
/// </para>
/// <para>
/// It is the actual test fixture's responsibility to launch the browser. (Usually in the test fixture setup)
/// </para>
/// </summary>
protected override void CreateBrowser()
{
switch (BrowserType)
{
case BrowserTypeEnum.Chrome:
Browser = new ChromeDriver();
break;
case BrowserTypeEnum.Firefox:
Browser = new FirefoxDriver();
break;
case BrowserTypeEnum.InternetExplorer:
Browser = new IEDriver();
break;
default:
break;
}
}
可能不是最好的解决方案,但我发现它非常易读。另一种方法是使用Selenium Grid之类的东西,或者将驱动程序类型传递给NUnit并直接创建它。你已经尝试过这个(通过直接类型的驱动程序),它似乎不是你想要的。唯一的区别可能是您将驱动程序类型传入测试夹具,而不是实际测试。
另一种方法是,如果您使用CI服务器解决方案,请创建配置设置以指示要用于测试的浏览器。让CI驱动程序重复测试三次,每次都编辑该配置设置。
我同意,知道他们正在使用什么样的驱动程序并不是实际的测试责任,这就是为什么我将这个责任推到测试夹具中。我这样做的方式可能不是最“优雅”的方式,但它至少对我来说是最可读的。有人看着我的代码可以很容易地看到这个测试夹具正在重复,以及哪些浏览器正在重复这些步骤。
对我来说,驱动程序的创建必须始终在实际的TestFixture中(不是基础测试夹具)。原因是因为在打开浏览器之前我想要做一些逻辑 - 如果这个逻辑失败(在Setup或TestFixtureSetup方法中),那么NUnit将不会运行任何拆卸方法。因此浏览器窗口将保持打开状态。
所以为了解决这个问题,在测试运行之前,我在TestFixtureSetup中做的最后一件事叫做“CreateBrowser”。
答案 2 :(得分:0)
您也可以为NUnit编写自己的 TestCaseProvider addin ,以便在所有浏览器上执行此迭代。
然后创建一个像这样的新属性
[Test, TestOnAllBrowsers]
public void SomeTest(IWebDriver driver)
{
driver.Navigate().GoToUrl("...");
}
标记应在所有浏览器上运行的所有测试,并填充 TestCaseProvider插件中的driver
变量。但是,如果您已使用TestCase
属性,则可能会变得复杂。