1

I want to close browsers after completion of all test. Problem is I am not able to close the browser since the object created ThreadLocal driver does not recognize the driver after completion of test value returning is null.

Below is my working code

package demo;

import java.lang.reflect.Method;
import org.openqa.selenium.By;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class ParallelMethodTest {
    private static ThreadLocal<dummy> driver;
    private int input;
    private int length;

    @BeforeMethod
    public void beforeMethod() {
        System.err.println("Before ID" + Thread.currentThread().getId());
        System.setProperty("webdriver.chrome.driver", "chromedriver.exe");
        if (driver == null) {
            driver = new ThreadLocal<dummy>();
        }
        if (driver.get()== null) {
            driver.set(new dummy());
        }

    }

    @DataProvider(name = "sessionDataProvider", parallel = true)
    public static Object[][] sessionDataProvider(Method method) {
        int len = 12;

        Object[][] parameters = new Object[len][2];
        for (int i = 0; i < len; i++) {
            parameters[i][0] = i;
            parameters[i][1]=len;

        }
        return parameters;
    }

    @Test(dataProvider = "sessionDataProvider")
    public void executSessionOne(int input,int length) {
        System.err.println("Test ID---" + Thread.currentThread().getId());
        this.input=input;
        this.length=length;
        // First session of WebDriver
        // find user name text box and fill it
        System.out.println("Parameter size is:"+length);
        driver.get().getDriver().findElement(By.name("q")).sendKeys(input + "");
        System.out.println("Input is:"+input);

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    @AfterMethod
    public void afterMethod() {
    System.err.println("After ID" + Thread.currentThread().getId());
    driver.get().close();

    }


}

package demo;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.AfterClass;

public class dummy  {

    public WebDriver getDriver() {
        return newDriver;
    }

    public void setNewDriver(WebDriver newDriver) {
        this.newDriver = newDriver;
    }

    private WebDriver newDriver;

    public dummy() {
        newDriver = new ChromeDriver();
        newDriver.get("https://www.google.co.in/");
    }

    @AfterClass
    public void close(){
        if(newDriver!=null){
            System.out.println("In After Class");
            newDriver.quit();
        }
    }
}

Thanks in Advance.

manish
  • 49
  • 2
  • 5

3 Answers3

2

private static ThreadLocal<dummy> driver is added at the class level. What is happening is that you have already declared the variable at class level. i.e. memory is already allocated to it. Multiple threads are just setting and resetting the values of the same variable.

What you need to do is create a factory that will return an instance of Driver based on a parameter you pass to it.Logic can be anything but taking a general use case example the factory will create a new object and return only if an existing object doesn't exist. Declare and initialise the driver (from factory) in your @Test Methods

Sample code for the factory would be something like

static RemoteWebDriver firefoxDriver;
static RemoteWebDriver someOtherDriver;


static synchronized RemoteWebDriver getDriver(String browser, String browserVersion, String platform, String platformVersion)
{
if (browser == 'firefox')
{
  if (firefoxDriver == null)
  {
                DesiredCapabilities cloudCaps = new DesiredCapabilities();
                cloudCaps.setCapability("browser", browser);
                cloudCaps.setCapability("browser_version", browserVersion);
                cloudCaps.setCapability("os", platform);
                cloudCaps.setCapability("os_version", platformVersion);
                cloudCaps.setCapability("browserstack.debug", "true");
                cloudCaps.setCapability("browserstack.local", "true");

                firefoxDriver = new RemoteWebDriver(new URL(URL),cloudCaps); 
}
}
else
{
if (someOtherDriver == null)
  {
                 DesiredCapabilities cloudCaps = new DesiredCapabilities();
                cloudCaps.setCapability("browser", browser);
                cloudCaps.setCapability("browser_version", browserVersion);
                cloudCaps.setCapability("os", platform);
                cloudCaps.setCapability("os_version", platformVersion);
                cloudCaps.setCapability("browserstack.debug", "true");
                cloudCaps.setCapability("browserstack.local", "true");

                someOtherDriver = new RemoteWebDriver(new URL(URL),cloudCaps); 
}
return someOtherDriver;
}
1

You have a concurrency issue: multiple threads can create a ThreadLocal instance because dummy == null can evaluate to true on more than one thread when run in parallel. As such, some threads can execute driver.set(new dummy()); but then another thread replaces driver with a new ThreadLocal instance.

In my experience it is simpler and less error prone to always use ThreadLocal as a static final to ensure that multiple objects can access it (static) and that it is only defined once (final).

You can see my answers to the following Stack Overflow questions for related details and code samples:

Community
  • 1
  • 1
mfulton26
  • 29,956
  • 6
  • 64
  • 88
0

This is happening because you are creating the driver instance in beforeMethod function so it's scope ends after the function ends.

So when your afterMethod start it's getting null because webdriver instance already destroy as beforeMethod function is already completed.

Refer below links:-

http://www.java-made-easy.com/variable-scope.html

What is the default scope of a method in Java?

Community
  • 1
  • 1
Shubham Jain
  • 16,610
  • 15
  • 78
  • 125
  • please find my updated code. i have initialized driver in ThreadLocal. i don't think so there is scope issue. – manish Feb 09 '16 at 10:11