2015-10-01 41 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方法的情況,我整理了一下。事情似乎現在好多了,司機不會感到困惑,截圖正在附加到正確的瀏覽器/測試。

相關問題