2

我们最近开始使用 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 框架执行整套测试并在每次运行时为各个测试注入不同的参数?或者还有其他好的解决方案吗?

4

3 回答 3

6

您应该能够使用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("...");
    ...
}
于 2012-09-11T15:14:45.857 回答
4

没有“最好”的方法可以做到这一点,但是我完成的方法如下:

我创建了一个枚举:

/// <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 驱动程序重复测试 3 次,每次都编辑该配置设置。

我同意,知道他们正在使用什么样的驱动程序并不是实际的测试责任,这就是为什么我把这个责任推到测试夹具中。我这样做的方式可能不是最“优雅”的方式,但至少对我来说是最易读的。看我的代码的人可以很容易地看到这个测试夹具正在重复,以及哪些浏览器正在重复这些步骤。

对我来说,驱动程序的创建必须始终在实际的 TestFixture 中(而不是基本测试夹具)。原因是因为在打开浏览器之前我想做一些逻辑 - 如果这个逻辑失败(在 Setup 或 TestFixtureSetup 方法中),那么 NUnit 将不会运行任何拆卸方法。因此,浏览器窗口将保持打开状态。

所以为了解决这个问题,我在 TestFixtureSetup 中做的最后一件事,在测试运行之前,叫做“CreateBrowser”。

于 2012-09-11T15:09:13.630 回答
0

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

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

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

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

于 2013-04-09T18:01:33.847 回答