对多个驱动程序运行WebDriver NUnit测试

我们最近开始使用WebDriver(支持Selenium 1)使用NUnit框架执行浏览器测试。 由于我们希望在各种浏览器中运行测试,因此我们为每个浏览器定义驱动程序,并在夹具设置期间将它们放入列表中:

[TestFixtureSetUp] public void SetupTest() { // Load drivers Drivers = new List { 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框架执行整套测试并在每次运行中为各个测试注入不同的参数? 或者还有其他任何好的解决方案吗?

您应该能够使用TestCaseSourceAttribute 。 首先创建一个通常可访问的类,提供Web驱动程序的集合:

 public static class WebDriverFactory { public static IWebDriver[] Drivers = { new ChromeDriver(), new FirefoxDriver(), ... }; } 

接下来,实现如下所示的依赖于Web驱动程序的unit testing

 [Test, TestCaseSource(typeof(WebDriverFactory), "Drivers")] public void SomeTest(IWebDriver driver) { driver.Navigate().GoToUrl("..."); ... } 

(可选)要在实现每个unit testing时减少键入,还要定义一个新的Attribute类,该类inheritance自TestCaseSourceAttribute并且只实现默认构造函数:

 public class WebDriverSourceAttribute : TestCaseSourceAttribute { public WebDriverSourceAttribute() : base(typeof(WebDriverFactory), "Drivers") { } } 

使用inheritance的WedDriverSource属性,unit testing现在可以简化为:

 [Test, WebDriverSource] public void SomeTest(IWebDriver driver) { driver.Navigate().GoToUrl("..."); ... } 

没有“最好”的方法,但是我完成这个的方式如下:

我创建了一个枚举:

 ///  /// Enum that holds references to different browsers used in testing. ///  public enum BrowserTypeEnum { ///  /// Google Chrome. ///  Chrome, ///  /// Mozilla Firefox. ///  Firefox, ///  /// Internet Explorer. ///  InternetExplorer } 

在TestFixture中调用它是这样的:

 ///  /// Tests related to browsing Google ///  [TestFixture(BrowserTypeEnum.Chrome)] [TestFixture(BrowserTypeEnum.Firefox)] public class GoogleTests : AbstractTestFixture { } 

在AbstractTestFixture中:

  ///  /// Create's the browser used for this test fixture. ///  /// Must always be called as part of the test fixture set up. ///  ///  /// It is the actual test fixture's responsibility to launch the browser. (Usually in the test fixture setup) ///  ///  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”。

您也可以为NUnit编写自己的TestCaseProvider插件 ,以便在所有浏览器上执行此迭代。

然后创建一个这样的新属性

 [Test, TestOnAllBrowsers] public void SomeTest(IWebDriver driver) { driver.Navigate().GoToUrl("..."); } 

标记应在所有浏览器上运行的所有测试并填充TestCaseProvider插件中driver变量。 但是,如果您已经使用TestCase属性,这可能会变得复杂。