【问题标题】:How to avoid empty extra browser opens when running parallel tests with TestNG使用 TestNG 运行并行测试时如何避免打开额外的空浏览器
【发布时间】:2016-01-06 19:06:21
【问题描述】:

当我使用 TestNG 和 selenium-webdriver 运行并行测试用例时,有一些浏览器实例打开为空并且即使在执行完成后也不会关闭。我在不同的论坛上阅读了几个主题,询问类似的问题,但似乎都不是同一个问题。

当我向套件添加更多测试时,似乎打开了更多空浏览器。我不确定以下哪些信息与此问题相关,但我会尽力提供我所拥有的完整信息:

  • 我正在使用(如前所述)TestNG - webdriver。
  • 我正在使用页面对象模式。
  • 我正在从 javafx 界面运行自动化,它允许用户选择一些选项。
  • 我正在使用 ChromeDriver 来模拟移动设备。
  • 我正在使用驱动程序的本地线程,它允许我为每个测试使用专有的静态驱动程序。
  • 当我不并行运行时,没有打开任何空的浏览器。

这是我的 TestNg.xml:

<suite name="Suite" parallel="classes" thread-count="4">
<test name="Test">
<groups>
     <run>
        <!-- Use include to specify what you want to run or exclude to not run the mentioned group(s) -->
        <include name="fullRegression"/>
        <exclude name="brokenOrDevelopment"/>
     </run>
  </groups>
<packages>
    <!-- Packages who contains the test cases classes -->
    <package name="Test"/>       
</packages>

这是创建驱动程序实例的类

public class TestCaseConfiguration {
 protected HomePageObjects homePage = null;
 protected DesiredCapabilities  capabilities;
 protected ExtentReports REPORTMANAGER;
 protected ExtentTest REPORT;

 public static ThreadLocal<ChromeDriver> driver;

 @BeforeMethod(alwaysRun = true)
 public void setup() throws InterruptedException {

     System.setProperty("webdriver.chrome.driver", "src/Tools/chromedriver.exe");//chrome driver version 2.20 | We need to have a relative path since no all the user will have the driver on C: 

     capabilities = DesiredCapabilities.chrome();
     Map<String, String> mobileEmulation = new HashMap<String, String>();
     mobileEmulation.put("deviceName", Constants.DEVICE);
     Map<String, Object> chromeOptions = new HashMap<String, Object>();
     chromeOptions.put("mobileEmulation", mobileEmulation);

     capabilities.setCapability(ChromeOptions.CAPABILITY, chromeOptions);

     /**
      * dirver is a ThreadLocal<ChromeDriver>. This allows the driver to be static and available for the complete project, and exclusive for each thread. 
      */
     driver=new ThreadLocal<ChromeDriver>()
                {
                    @Override
                    protected ChromeDriver initialValue()
                    {
                        return new ChromeDriver(capabilities); 
                    }
                };
     driver.get().manage().deleteAllCookies();
     driver.get().manage().timeouts().implicitlyWait(40, TimeUnit.SECONDS);
     driver.get().navigate().to(Constants.DOMAIN);

     homePage = PageFactory.initElements(driver.get(), HomePageObjects.class);
 }

 @AfterMethod(alwaysRun = true)
 public void close() throws InterruptedException {           
    driver.get().close();
    driver.get().quit();  
 }

}

这个类被每个测试用例类扩展。测试按预期运行,唯一的问题似乎是额外的浏览器实例。

没有人知道我该如何避免这个问题或者我做错了什么? 感谢您的帮助。

This is how the browser looks when open empty

【问题讨论】:

    标签: browser parallel-processing webdriver testng


    【解决方案1】:

    您正在创建一个新的 ThreadLocal&lt;ChromeDriver&gt; 实例并在每次运行 setup 时重新分配 driver。想象以下场景,其中setup 被多个线程并行调用:

    1. Thread0 创建一个ThreadLocal&lt;ChromeDriver&gt; 实例,将其分配给driver,并调用driver.get()。现在打开了一个浏览器。
    2. Thread1 创建一个ThreadLocal&lt;ChromeDriver&gt; 实例,将其分配给driver(替换由Thread0 分配给它的那个),并调用driver.get()。现在打开了两个浏览器,每个 ThreadLocal 实例一个。
    3. Thread0 再次调用driver.get(),但driver 不再引用相同的ThreadLocal 实例,因此打开了一个新浏览器。现在打开了三个浏览器,一个在“孤立”ThreadLocal 实例中,两个在引用的 ThreadLocal 中。

    现在想象一下这种情况,但有两个以上的线程!您将有很多“孤立的”ThreadLocal 实例四处飘荡,其中一些具有与某些线程关联的ChromeDriver 实例,但在任何线程上都没有引用ThreadLocal 的对象,以便“获取“他们。

    要解决此问题,我建议将driver 标记为final 并为其分配一次ThreadLocal 实例。

    例如

    public class TestCaseConfiguration {
        protected HomePageObjects homePage = null;
        protected ExtentReports REPORTMANAGER;
        protected ExtentTest REPORT;
    
        public static final ThreadLocal<ChromeDriver> driver;
        private static final Set<ChromeDriver> drivers = Collections.newSetFromMap(new ConcurrentHashMap<>());
        static {
            System.setProperty("webdriver.chrome.driver", "src/Tools/chromedriver.exe");//chrome driver version 2.20 | We need to have a relative path since no all the user will have the driver on C:
    
            DesiredCapabilities capabilities = DesiredCapabilities.chrome();
            Map<String, String> mobileEmulation = new HashMap<String, String>();
            mobileEmulation.put("deviceName", Constants.DEVICE);
            Map<String, Object> chromeOptions = new HashMap<String, Object>();
            chromeOptions.put("mobileEmulation", mobileEmulation);
    
            capabilities.setCapability(ChromeOptions.CAPABILITY, chromeOptions);
    
            /**
             * dirver is a ThreadLocal<ChromeDriver>. This allows the driver to be static and available for the complete project, and exclusive for each thread.
             */
            driver = new ThreadLocal<ChromeDriver>() {
                @Override
                protected ChromeDriver initialValue() {
                    ChromeDriver chromeDriver = new ChromeDriver(capabilities);
                    drivers.add(chromeDriver);
                    return chromeDriver;
                }
            };
        }
    
        @BeforeMethod(alwaysRun = true)
        public void setup() throws InterruptedException {
            driver.get().manage().deleteAllCookies();
            driver.get().manage().timeouts().implicitlyWait(40, TimeUnit.SECONDS);
            driver.get().navigate().to(Constants.DOMAIN);
    
            homePage = PageFactory.initElements(driver.get(), HomePageObjects.class);
        }
    
        @AfterSuite(alwaysRun = true)
        public void close() throws InterruptedException {
            for (ChromeDriver chromeDriver : drivers) {
                try {
                    chromeDriver.quit();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    【讨论】:

    • 嗨@mfulton26,谢谢你的代码实际上工作得很好,新的额外浏览器的问题似乎得到了解决。为了应用您的建议,我还需要对“@AferMethod”进行修改并将其替换为“@AfterSuite”,因为使用 aftermethod 当前代码驱动程序在第一个“driver.get().close( )' 但是现在由于某种原因,即使代码存在于'@AfterSuite'方法上,浏览器也没有关闭,我尝试了不同的方法来“解决”这个问题,但没有运气。你知道问题是什么吗?
    • 哦,是的...哈,我应该考虑到这一点。我稍后会更新我的代码示例。
    • @YohanDesanti 我已经更新了示例以跟踪所有驱动程序的集合并在@AfterSuite(而不是@AfterMethod)中退出它们。祝你好运!
    【解决方案2】:

    我在每个测试用例中调用的 libFile 中创建了单独的方法.. @图书馆文件

    //Variable declaration
    WebDriver driver=null;
    
    protected WebDriver getDriverInstance(){
       driver=new FirefoxDriver();
       return driver;
    }
    

    @testcase 类 - 我在 @BeforeMethod 中调用上述方法 //变量声明

    WebDriver driver=null;
    
    @BeforeMethod
    public void setUp(){
     driver=getDriverInstance();
    
    }
    

    这解决了我的多个空浏览器实例

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-13
      • 1970-01-01
      • 1970-01-01
      • 2020-04-25
      • 2018-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多