我正在使用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