2015-10-01 32 views
2

我正在使用selenium(selenium-server-standalone-2.47.1.jar)网格与TestNg进行并行测试,已启动通过ant,并使用TestListenerAdapter。屏幕截图是在听众的'onTestFailure'方法中进行的。问题在于侦听器似乎会弄清楚应该使用哪个驱动程序,并且有时会截取错误的浏览器窗口,或者如果它认为它应该使用的驱动程序已经退出,则完全失败。使用Selenium和TestNg,TestListenerAdapter获得测试混合,驱动程序似乎在测试类之间获得共享

当测试开始时,TestNg的@BeforeTest和TestListenerAdapter的'onTestStart'方法在同一个线程上运行,但是当测试失败时,TestListenerAdapter的'onTestFailure'方法似乎在单独的线程上运行。似乎线程越过/共享某种方式,但我不明白为什么。

这里是一些骨架代码,非常感谢任何帮助。

基础测试类:

public class baseClassTests{ 

    protected AutomationUtils au; 
    protected DriverUtils du; 

    @BeforeTest(alwaysRun = true) 
    @Parameters({ "selenium.OS", "selenium.browser" }) 
    public void beforeTest(String OS, String browser) { 

     //these call simple private methods to know where to set up the driver 
     String port = getPort(OS, browser); 
     String host = getHost(OS); 

     //make a driver utility object here, this makes a driver 
     du = new DriverUtils(browser, host, port); 

     //pass this driver utility object to another class of utilities 
     //this 'AutomationUtils' class gets a RemoteWebDriver ('driver') by calling driver=du.getDriver(); 
     //the 'AutomationUtils' class is then the one that does all of the 'driver.findBy...' etc 
     au = new AutomationUtils(du); 
    } 


    @BeforeMethod(alwaysRun = true) 
    public void beforeMethod(Method m, ITestResult tr) { 
     du.deleteCookies(); 
     testNgTestName = m.getName(); 
     print("Method: "+testNgTestName + " Thread: "+Thread.currentThread().hashCode()); 
     //set the attribute of the ITestResult object so we can use the same object in the listener 
     tr.setAttribute("du", du); 
     tr.setAttribute("au", au); 
    } 

} 

Listener类

public class AmSimpleTestListener extends TestListenerAdapter { 

    private DriverUtils driveU; 
    private AutomationUtils AutoU; 
    private RemoteWebDriver driver; 
    private RemoteWebDriver augmentedDriver; 
    private String methodName; 
    private String browser; 
    private String browserVersion; 
    String testClass; 




    @Override 
    public void onTestStart(ITestResult tr) { 
     //pick up the correct driver utility object from the test class/method we are in 
     driveU = (DriverUtils) tr.getAttribute("du"); 
     AutoU = (AutomationUtils) tr.getAttribute("au"); 
     driver = du.getDriver(); 
     augmentedDriver = (RemoteWebDriver) new Augmenter().augment(driver); 
     methodName = tr.getName(); 
     testClass=tr.getTestClass(); //sort of, I actually parse it up a bit 
     browser = driveU.getBrowser(); 
     browserVersion = driveU.getBrowserVersion(); 
     print("Method: "+methodName + " Thread: "+Thread.currentThread().hashCode()); 
    } 

    @Override 
    public void onTestFailure(ITestResult tr) { 
     print("Method: "+tr.getName() + " Thread: "+Thread.currentThread().hashCode()); 
     try{ 
      writeScreenshotFile(); 
     } 
     catch (Exception e){ 
      Out.error("Unable to take screen shot"); 
      e.printStackTrace(); 
     } 
    } 


    private String writeScreenshotFile() { 
     if (driver != null && driver.getSessionId() != null) { 
      File scrShot = ((TakesScreenshot) augmentedDriver).getScreenshotAs(OutputType.FILE); 
      File localPathToScreenShot = new File("/path/to/base/directory/"+testClass+"/"+methodName+".png"); 
      try { 
       FileUtils.copyFile(scrShot, localPathToScreenShot); 
      } catch (Exception e) { 
       Out.error("Couldn't write screenshot to file"); 
      } 
      return localPathToScreenShot.getAbsolutePath(); 
     } 
     return "Could not get path."; 
    } 

} 

DriverUtils类使/提供了驱动程序

public class DriverUtils { 

    private RemoteWebDriver driver; 
    private int timeout; 
    private String browserVersion; 
    private String browser 
    private DesiredCapabilities caps; 

    public DriverUtils(String browser, String host, String port) { 
     String hostUrl = "http://" + host + ":" + port + "/wd/hub"; 
     this.browser=browser; 
     //do some stuff here to set capabilties 
     driver = new RemoteWebDriver(new URL(hostUrl), caps); 
     browserVersion = driver.getCapabilities().getVersion(); 
    } 

    public RemoteWebDriver getDriver() { 
     return driver; 
    } 

    public AmBrowser getBrowser() { 
     return browser; 
    } 

    public String getBrowserVersion() { 
     return browserVersion; 
    } 


    public void quitDriver() { 
     driver.quit(); 
    } 

    public void deleteCookies(){ 
     driver.manage().deleteAllCookies(); 
    } 


} 


public class AutomationUtils extends BaseClassUtils { 

    public AutomationUtils(DriverUtils driverUtils) { 
     //pass it up to the base class utils (this is different than base class tests, above) 
     //do this so the driver can be accessed by other utility classes as well 
     super(driverUtils); 
    } 

    //All sorts of methods here to find elements, login, blah blah everything that is done with a driver object 
} 


public class BaseClassUtils { //this is a different class than BaseClassTests 

    //make the driver a protected object so all utility classes can access as nec. 
    protected final RemoteWebDriver driver; 

    public BaseClassUtils(DriverUtils driverUtils) { 
     driver = driverUtils.getDriver(); 
    } 

} 

测试通过蚂蚁运行。

<suite name="Dev2 for debugging" parallel="tests" thread-count="10">-- tests here </suite> 

回答

0

尝试使用一个ThreadLocal的RemoteWebDriver所以它可以处理并行运行:

public class DriverUtils { 
    private static ThreadLocal<RemoteWebDriver> driver = new ThreadLocal<~>(); 
    private int timeout; 
    private String browserVersion; 
    private String browser 
    private DesiredCapabilities caps; 

    public DriverUtils(String browser, String host, String port) { 
     String hostUrl = "http://" + host + ":" + port + "/wd/hub"; 
     this.browser=browser; 
     //do some stuff here to set capabilties 
     driver.set(new RemoteWebDriver(new URL(hostUrl), caps)); 
     browserVersion = getDriver().getCapabilities().getVersion(); 
    } 

    public RemoteWebDriver getDriver() { 
     return driver.get(); 
    } 

    public AmBrowser getBrowser() { 
     return browser; 
    } 

    public String getBrowserVersion() { 
     return browserVersion; 
    } 


    public void quitDriver() { 
     getDriver().quit(); 
    } 

    public void deleteCookies(){ 
     getDriver().manage().deleteAllCookies(); 
    } 
} 
+0

谢谢,我试过你的建议,但它似乎没有办法。看起来会发生的事情是'@BeforeTest'(beforeTest)方法似乎在同一个线程上启动多个测试类,并造成严重后果。当我在'@BeforeTest'(beforeTest)中记录线程时,对于3个测试类,它似乎只使用2个线程启动... TRACE:在线程上的AcceptanceTests.ErrorReportingTests之前开始:1151820366 TRACE:从beforeTest开始接受TestTests.PopupTests在线程上:1227297304 TRACE:在线程上的AcceptanceTests.CalendarPageTests之前启动:1227297304 – JackhammersForWeeks

+0

除了使用TestNg并行运行时确实需要的ThreadLocal更改,请尝试在BaseClassUtils非最终(受保护的RemoteWebDriver驱动程序;)中创建RemoteWebDriver并查看如果有帮助。 – Shane

+0

试过,谢谢,但同样的问题。这个问题似乎是'@BeforeTest'beforeTest方法在同一个线程上启动两个测试类。一旦两个类在同一个线程上运行,我就会崩溃,没有任何东西会使驱动程序分离。我无法弄清楚为什么测试类不能在单独的线程上启动。 – JackhammersForWeeks

1

摆弄了一会儿后,我得出的结论,有这似乎极大的帮助两件事情。 1)消除监听器,并在@AfterMethod中获取所有屏幕截图。 2)将@ Before/After Method/Test方法移动到子类中,而只需调用父类中的方法来完成所有工作。我注意到的另一件事是,对于#2,TestNG应该运行父'@Before'方法,然后运行子'@Before'方法;然后在最后运行孩子的'@After'方法,然后运行父'@After'方法。我运行了一系列简单的测试,发现所有之前/之后的方法都没有运行,所以对于少数我在父代和子代都使用@Before和@After方法的情况,我整理了一下。事情似乎现在好多了,司机不会感到困惑,截图正在附加到正确的浏览器/测试。

相关问题