我正在使用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>
谢谢,我试过你的建议,但它似乎没有办法。看起来会发生的事情是'@BeforeTest'(beforeTest)方法似乎在同一个线程上启动多个测试类,并造成严重后果。当我在'@BeforeTest'(beforeTest)中记录线程时,对于3个测试类,它似乎只使用2个线程启动... TRACE:在线程上的AcceptanceTests.ErrorReportingTests之前开始:1151820366 TRACE:从beforeTest开始接受TestTests.PopupTests在线程上:1227297304 TRACE:在线程上的AcceptanceTests.CalendarPageTests之前启动:1227297304 – JackhammersForWeeks
除了使用TestNg并行运行时确实需要的ThreadLocal更改,请尝试在BaseClassUtils非最终(受保护的RemoteWebDriver驱动程序;)中创建RemoteWebDriver并查看如果有帮助。 – Shane
试过,谢谢,但同样的问题。这个问题似乎是'@BeforeTest'beforeTest方法在同一个线程上启动两个测试类。一旦两个类在同一个线程上运行,我就会崩溃,没有任何东西会使驱动程序分离。我无法弄清楚为什么测试类不能在单独的线程上启动。 – JackhammersForWeeks