1

I have a selenium project that is running parallel tests via testng. When the test fails I have a listener class that captures the screenshot. The class is as follows

public class ScreenshotOnFailure extends TestListenerAdapter {

@Override
public void onTestFailure(ITestResult tr) {
    WebDriver driver = SeleniumSetup.driverrunning;
    boolean hasQuit = driver.toString().contains("(null)");
    if(!hasQuit){
        System.out.println(driver);
        File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
        DateFormat dateFormat = new SimpleDateFormat("dd_MMM_yyyy__hh_mm_ssaa");
        Date date = new Date();
        String NewFileNamePath = null;
        File directory = new File(".");
        String methodName = tr.getMethod().getMethodName();
        try {
            NewFileNamePath =directory.getCanonicalPath() + "\\target\\surefire-reports\\html\\Screenshots\\"+methodName+"_"+ dateFormat.format(date) +"Listener.png";
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }


        try {
            FileUtils.copyFile(scrFile, new File(NewFileNamePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
        String reportFilePath = ".\\Screenshots\\"+methodName+"_"+ dateFormat.format(date) +".png";
        System.setProperty("org.uncommons.reportng.escape-output", "false");    
        Reporter.log("<a href=" + reportFilePath + ">Click to open screenshot</a><img src=" + reportFilePath +  " height='350' width='700'>");      
    }
}}

In my tests I have a AfterMethod that cleans up the test

    @AfterMethod(alwaysRun = true)
public void tearDown() throws Exception
{
    driver.quit();
}

If test are run one by one then the correct browser screenshot is captured however if I run parrallel testsit captures the wrong test browser. I think the problem may be one of the following

  • The after method has already quit the browser(This is a case sometimes thus why I had to add the hasQuit boolean)
  • The listene is referencing the wrong driver object. I believe this is the problem but I'm not sure how to make sure it references the correct driver.

I have a workaround that work which pretty much invloves creating a static screen capture object and then adding that to the AfterMethod, However this is less than ideal as I would like to use a listener.

Ray
  • 1,134
  • 10
  • 27
  • Are you sure that selenium is focusing on the right window? If you open a new tab (for instance), selenium continues to use the old tab unless you explicitly switch to the new one. When you pull driver running, you may be pulling either the first or the last started driver. – Brydenr Sep 23 '16 at 18:33
  • @Brydenr Yes I believe it may be pulling the last driver started. I'm not sure how to get it to pull the correct driver. Any ideas? – Ray Sep 23 '16 at 18:38
  • to switch tabs, you use window handles http://stackoverflow.com/questions/19112209/how-to-handle-the-new-window-in-selenium-webdriver-using-java – Brydenr Sep 23 '16 at 18:39

1 Answers1

3

From your code WebDriver driver = SeleniumSetup.driverrunning, It seems like driverrunning is static driver instance in SeleniumSetup class. So, in parallel execution it may reference to a wrong driver object.

ThreadLocal may help you to create a thread safe driver object, below is an example.

public class DriverFactory
{

   private DriverFactory()
   {
      //Do-nothing..Do not allow to initialize this class from outside
   }
   private static DriverFactory instance = new DriverFactory();

   public static DriverFactory getInstance()
   {
      return instance;
   }

   ThreadLocal<WebDriver> driver = new ThreadLocal<WebDriver>() // thread local driver object for webdriver
   {
      @Override
      protected WebDriver initialValue()
      {
         return new FirefoxDriver(); // can be replaced with other browser drivers
      }
   };

   public WebDriver getDriver() // call this method to get the driver object and launch the browser
   {
      return driver.get();
   }

   public void removeDriver() // Quits the driver and closes the browser
   {
      driver.get().quit();
      driver.remove();
   }
}

Use DriverFactory to get driver instance.

WebDriver driver = DriverFactory.getInstance().getDriver();
Amit Bhoraniya
  • 621
  • 3
  • 14
  • You have to pass driver name as a parameter in testng config file, this may help you. http://stackoverflow.com/questions/26604745/parameterized-selenium-tests-in-parallel-with-testng – Amit Bhoraniya Sep 23 '16 at 19:41
  • Thanks for the advice. I implemented the class and it worked a charm. I also added a setter method so that could build the driver based on browser type etc. – Ray Oct 13 '16 at 16:49