【问题标题】:How do I test multiple browsers with selenium and a single NUnit suite and keep it DRY?如何使用 selenium 和单个 NUnit 套件测试多个浏览器并使其保持干燥?
【发布时间】:2019-07-31 02:12:20
【问题描述】:

我正在寻找一种方法来重用一个 NUnit 测试套件,而无需为每个浏览器复制整个套件。似乎我需要为每个浏览器安装一个新设备。我可以从 NUnit gui 发送某种环境变量或配置设置来切换浏览器吗?见下文:

[TestFixture]
public class User
{
    private ISelenium selenium;
    private StringBuilder verificationErrors;

    [SetUp]
    public void SetupTest()
    {
        // TheBrowser = How do I populate this variable from the NUnit gui? 
        selenium = new DefaultSelenium("localhost", 4444, **TheBrowser**, "http://localhost:52251/");
        selenium.Start();
        verificationErrors = new StringBuilder();
    }

    [TearDown]
    public void TeardownTest()
    {
      ...
    }

    [Test]
    public void SearchUser()
    {
       ... 
    }

}

【问题讨论】:

    标签: selenium nunit cross-browser


    【解决方案1】:

    NUnit 2.5+ 支持通用测试装置,这使得在多个浏览器中的测试非常简单。 http://www.nunit.org/index.php?p=testFixture&r=2.5

    构建以下将创建两个“GoogleTest”NUnit 测试,一个用于 Firefox,一个用于 IE。

    using NUnit.Framework;
    using OpenQA.Selenium;
    using OpenQA.Selenium.Firefox;
    using OpenQA.Selenium.IE;
    using System.Threading;
    
    namespace SeleniumTests 
    {
        [TestFixture(typeof(FirefoxDriver))]
        [TestFixture(typeof(InternetExplorerDriver))]
        public class TestWithMultipleBrowsers<TWebDriver> where TWebDriver : IWebDriver, new()
        {
            private IWebDriver driver;
    
            [SetUp]
            public void CreateDriver () {
                this.driver = new TWebDriver();
            }
    
            [Test]
            public void GoogleTest() {
                driver.Navigate().GoToUrl("http://www.google.com/");
                IWebElement query = driver.FindElement(By.Name("q"));
                query.SendKeys("Bread" + Keys.Enter);
    
                Thread.Sleep(2000);
    
                Assert.AreEqual("bread - Google Search", driver.Title);
                driver.Quit();
            }
        }
    }
    

    【讨论】:

    • 如何使用这种方法设置浏览器功能? (例如我需要以私有模式启动每个浏览器)谢谢。
    【解决方案2】:

    好问题,很多人都遇到过这个问题。我喜欢使用 IoC 容器将我的浏览器注入到我的测试用例中。这让我可以将所有浏览器配置放入一个注入“mudule”中

    我使用 Java 绑定和 Guice 作为我的 IoC 容器,但 .Net 中的主体是相同的。您希望类中的 DefaultSelnium 字段被注入。然后,您的测试将使用此对象并在完成后将其处理掉。您可能会发现可以立即注入它,或者您可能需要在 setup 方法中创建对象。根据您的单元测试框架,您应该注意以下几点:

    • 您的测试类是否为每个测试创建新的? JUnit 为每个要运行的测试创建一个新的测试类实例。 TestNG 著名地取消了这一点,为每个包含的测试重用测试类对象。重用的问题是您注入的 DefaultSelenium 实例是随车携带的,如果您的测试并行运行或更改浏览器状态,这可能会导致问题。
    • 延迟加载您的浏览器对象如果您的单元测试工具立即加载所有测试类,它会尝试预先创建浏览器对象,这会占用大量资源。

    我相信你可以比我更好地自己用谷歌搜索,但这些是我认为很有希望的一些 DI 和 NUnit 链接。

    NUnit integration tests and dependency injection

    http://buildstarted.com/2010/08/24/dependency-injection-with-ninject-moq-and-unit-testing/

    如果您不喜欢 DI,我听说有人使用工厂方法根据一些外部设置生成浏览器。

    【讨论】:

      【解决方案3】:

      这是一个使用自定义 XUnit DataAttribute 为测试提供驱动程序的示例单元测试

      using OpenQA.Selenium;
      using SeleniumPageObjectsPatternExample.Attributes;
      using SeleniumPageObjectsPatternExample.PageObjects;
      using Xunit;
      using Xunit.Extensions;
      
      public class HomepageTests 
      {
          [Theory]
          [Browser(Type.Firefox)]
          [Browser(Type.GoogleChrome)]
          public void HomepageLinksToBlogPage(IWebDriver webDriver)
          {
              // arrange 
              var expected = "some expected value";
      
              // act
              var homepage = new HomePage(webDriver, true);
      
              // assert
              Assert.True(homepage.BlogLink.Displayed);
              Assert.Equal(expected, homepage.Header.Text);
          }
      }
      

      这里是自定义的DataAttribute

      using System.Reflection;
      using OpenQA.Selenium;
      using SeleniumPageObjectsPatternExample.WebDriver;
      using Xunit.Extensions;
      
      public class BrowserAttribute : DataAttribute
      {
          private IWebDriver WebDriver { get; set; }
      
          public BrowserAttribute(Type browser)
          {
              this.WebDriver = WebDriverFactory.Create(browser);
          }
      
          public override IEnumerable<object[]> GetData(MethodInfo methodUnderTest, System.Type[] parameterTypes)
          {
              return new[] { new[] { this.WebDriver } };
          }
      }
      

      使用这个 WebDriverFactory

      using OpenQA.Selenium;
      using OpenQA.Selenium.Chrome;
      using OpenQA.Selenium.Firefox;
      
      using Type = SeleniumPageObjectsPatternExample.Attributes.Type;
      
      public class WebDriverFactory
      {
          public static IWebDriver Create(Type browser)
          {
              IWebDriver webDriver;
      
              switch (browser)
              {
                  case Type.Firefox:
                      webDriver = new FirefoxDriver();
                      break;
                  case Type.GoogleChrome:
                      webDriver = new ChromeDriver();
                      break;
                  default:
                      webDriver = new ChromeDriver();
                      break;
              }
      
              webDriver.Manage().Window.Maximize();
      
              return webDriver;
          }
      }
      

      以及浏览器类型枚举

      public enum Type
      {
          Firefox,
          GoogleChrome
      }
      

      我建议您将枚举的名称从 Type 更改为其他名称...

      【讨论】:

        【解决方案4】:

        我推荐 Lucifer 解决方案的一个重要变体。让属性为 Fact/Theory 方法提供工厂,而不是驱动程序。为什么?好吧,当你看到所有这些浏览器窗口弹出时(n x m,其中 n = 测试数,m = 每个测试的浏览器数),你会决定你只希望在测试实际运行时创建它们。

        因此,通过先前解决方案的更新,包括一些名称更改...

        using OpenQA.Selenium;
        using SeleniumPageObjectsPatternExample.Attributes;
        using SeleniumPageObjectsPatternExample.PageObjects;
        using Xunit;
        using Xunit.Extensions;
        
        namespace SeleniumHelpers
        {    
            public class HomepageTests 
            {
                [Theory]
                [WebDriver(DriverType.Firefox)]
                [WebDriver(DriverType.GoogleChrome)]
                public void HomepageLinksToBlogPage(WebDriverFactory factory)
                {
                    // arrange 
                    IWebDriver webDriver = factory.Create(); // Browser starts here.
                    var expected = "some expected value";
        
                    // act
                    var homepage = new HomePage(webDriver, true);
        
                    // assert
                    Assert.True(homepage.BlogLink.Displayed);
                    Assert.Equal(expected, homepage.Header.Text);
        
                    // Optional cleanup (better wrapped in try/finally for entire method).
                    webDriver.Quit();
                    webDriver.Dispose();
                }
            }
        }
        

        更新了 DataAttribute...(注意,我更正了 GetData() 方法的签名以适用于最新的 xUnit。)

        using System.Reflection;
        using OpenQA.Selenium;
        using Xunit.Extensions;
        
        namespace SeleniumHelpers
        {    
            public class WebDriverAttribute : DataAttribute
            {
                private WebDriverFactory WebDriverFactory { get; set; }
        
                public WebDriverAttribute(Type browser)
                {
                    this.WebDriver = WebDriverFactory.Create(browser);
                }
        
                public override IEnumerable<object[]> GetData(MethodInfo methodUnderTest)
                {
                    return new[] { new[] { this.WebDriverFactory } };
                }
            }
        }
        

        新的 WebDriverFactory

        using OpenQA.Selenium;
        using OpenQA.Selenium.Chrome;
        using OpenQA.Selenium.Firefox;
        
        namespace SeleniumHelpers
        {    
            public enum DriverType
            {
                Firefox,
                GoogleChrome
            }
        
            public class WebDriverFactory
            {
                private DriverType _driverType;
                public WebDriverFactory(DriverType driverType)
                {
                    _driverType = driverType;
                }
        
                public static IWebDriver Create(Type browser)
                {
                    IWebDriver webDriver;
        
                    switch (browser)
                    {
                        case Type.Firefox:
                            webDriver = new FirefoxDriver();
                            break;
                        case Type.GoogleChrome:
                            webDriver = new ChromeDriver();
                            break;
                        default:
                            webDriver = new ChromeDriver();
                            break;
                    }
        
                    webDriver.Manage().Window.Maximize();
        
                    return webDriver;
                }
            }
        }
        

        【讨论】:

          【解决方案5】:
          [SetUp]
              public void CreateDriver()
              {
          
          
                  //driver = new TWebDriver();
                  if (typeof(TWebDriver).Name == "ChromeDriver")
                  {
                      ChromeOptions options = new ChromeOptions();
                      options.AddArguments("--incognito");
                      driver = new ChromeDriver(options);
                  }
                  else if (typeof(TWebDriver).Name == "FirefoxDriver")
                  {
                      FirefoxOptions options = new FirefoxOptions();
                      options.UseLegacyImplementation = false;
                      options.SetPreference("browser.private.browsing.autostart", true);
                      options.AddArgument("-private");
                      driver = new FirefoxDriver(options);
                  }
                  else if (typeof(TWebDriver).Name == "InternetExplorerDriver")
                  {
                      InternetExplorerOptions options = new InternetExplorerOptions();
                      options.BrowserCommandLineArguments = "-private";
                      options.EnsureCleanSession = true;
                      options.IgnoreZoomLevel = true;
                      options.EnablePersistentHover = true;
          
                      driver = new InternetExplorerDriver(options);
          
                  } else
                      driver = new TWebDriver();
              }
          

          【讨论】:

            猜你喜欢
            • 2017-01-28
            • 1970-01-01
            • 1970-01-01
            • 2016-08-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多