0

This is my test class where I want to execute each input of Data Provider in new browser parallely. I am able to open new browsers but I get Session Not Found Exception and no such element exception

public class DemoTest {
private WebDriver driver;
@Test(dataProvider = "dp")
public void f(Integer n, String s) {
  try {
      System.out.println("Driver: "+driver.toString());
      driver.get("www.google.com");
      driver.findElement(By.id("lst-ib")).sendKeys("1234567");
      System.out.println("method f id:"+Thread.currentThread().getId()+" n:"+n+" s:"+s);
  }
  catch(Exception e) {
      e.printStackTrace();
  }
}
@BeforeMethod
public void beforeMethod() {
  try {
  driver= new FirefoxDriver();
  driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
  driver.manage().window().maximize();
  System.out.println("Before method id:"+Thread.currentThread().getId());
  }
  catch (Exception e) {
      e.printStackTrace();
  }
 }

@AfterMethod
public void afterMethod() {
  try {
      System.out.println("After method id:"+Thread.currentThread().getId());
  if(driver != null ) {
  driver.quit();
 // driver.close();
  }
  }
  catch(Exception e) {
      e.printStackTrace();
  }
}


@DataProvider(parallel=true)
public Object[][] dp() {
return new Object[][] {
  new Object[] { 1, "a" },
  new Object[] { 2, "b" },
  new Object[] { 3, "c" },
  new Object[] { 4, "d" },

};
}
}

This is testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="Suite" parallel="methods"> 
<test name="prelogin">
<classes>
    <class name="com.package.DemoTest"></class>
</classes>
</test>
</suite> 

Could anyone tell me why I get this exception & how to solve it?

Grishma Oswal
  • 303
  • 1
  • 7
  • 22
  • Can you please provide the console output with full stack trace, etc.? – mfulton26 Dec 04 '15 at 13:03
  • By the way, I recommend not wrapping your code in try-catch blocks. If your BeforeMethod throws an exception then don't you want TestNG to skip test execution? TestNG will handle exceptions from tests and configuration methods and print stack traces for you. – mfulton26 Dec 04 '15 at 13:07

2 Answers2

4

You're sharing a WebDriver instance across multiple threads. As such, one test can try to use the WebDriver after another test's afterMethod has already quit it (hence the session not found exception) or hasn't loaded google.com yet (hence the no such element exception).

If you want to run Selenium WebDriver tests using TestNG in parallel then you can use a ThreadLocal to maintain a WebDriver instance per thread.

e.g.

public class DemoTest {
    private static final ThreadLocal<WebDriver> WEB_DRIVER_THREAD_LOCAL = new InheritableThreadLocal<>();

    @Test(dataProvider = "dp")
    public void f(Integer n, String s) {
        WebDriver driver = WEB_DRIVER_THREAD_LOCAL.get();
        System.out.println("Driver: " + driver.toString());
        driver.get("www.google.com");
        driver.findElement(By.id("lst-ib")).sendKeys("1234567");
        System.out.println("method f id:" + Thread.currentThread().getId() + " n:" + n + " s:" + s);
    }

    @BeforeMethod
    public void beforeMethod() {
        WebDriver driver = new FirefoxDriver();
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        driver.manage().window().maximize();
        WEB_DRIVER_THREAD_LOCAL.set(driver);
        System.out.println("Before method id:" + Thread.currentThread().getId());
    }

    @AfterMethod
    public void afterMethod() {
        WebDriver driver = WEB_DRIVER_THREAD_LOCAL.get();
        System.out.println("After method id:" + Thread.currentThread().getId());
        if (driver != null) {
            driver.quit();
        }
    }


    @DataProvider(parallel = true)
    public Object[][] dp() {
        return new Object[][]{
                new Object[]{1, "a"},
                new Object[]{2, "b"},
                new Object[]{3, "c"},
                new Object[]{4, "d"},

        };
    }
}

I've omitted wrapping each test with a try-catch block as TestNG already catches exceptions thrown by test/configuration methods and prints stack traces for them, etc.

The above example will create a WebDriver instance associated with the test's thread for each test. i.e. If they were to all run truly in parallel you would have 4 instances of Firefox open (which I think is what you want).

If you have more tests than threads and want to reuse WebDriver instances then you can use a ThreadLocal with an initial value.

e.g.

public class DemoTest {
    private static final Set<WebDriver> WEB_DRIVERS = new HashSet<>();
    private static final ThreadLocal<WebDriver> WEB_DRIVER_THREAD_LOCAL = InheritableThreadLocal
            .withInitial(new Supplier<WebDriver>() {
                @Override
                public WebDriver get() {
                    WebDriver driver = new FirefoxDriver();
                    driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
                    driver.manage().window().maximize();
                    WEB_DRIVERS.add(driver);
                    System.out.println("Before thread id:" + Thread.currentThread().getId());
                    return driver;
                }
            });

    @Test(dataProvider = "dp")
    public void f(Integer n, String s) {
        WebDriver driver = WEB_DRIVER_THREAD_LOCAL.get();
        System.out.println("Driver: " + driver.toString());
        driver.get("www.google.com");
        driver.findElement(By.id("lst-ib")).sendKeys("1234567");
        System.out.println("method f id:" + Thread.currentThread().getId() + " n:" + n + " s:" + s);
    }

    @AfterClass
    public void afterClass() {
        for (WebDriver webDriver : WEB_DRIVERS) {
            try {
                webDriver.quit();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    @DataProvider(parallel = true)
    public Object[][] dp() {
        return new Object[][]{
                new Object[]{1, "a"},
                new Object[]{2, "b"},
                new Object[]{3, "c"},
                new Object[]{4, "d"},

        };
    }
}

And a testng.xml to reduce the total number of threads to demonstrate this:

<suite name="Suite" parallel="methods" thread-count="2" data-provider-thread-count="2">
    <test name="prelogin">
        <classes>
            <class name="DemoTest"/>
        </classes>
    </test>
</suite>

Example output (see how it only creates 2 FirefoxDriver instances, runs two tests in parallel, and then runs the next two tests in parallel, using all the available threads and reusing the web drivers for each thread):

Before thread id:14
Driver: FirefoxDriver: firefox on WINDOWS (e924b5f1-9ace-46e5-a6b3-d1494de7e94d)
method f id:14 n:2 s:b
Before thread id:13
Driver: FirefoxDriver: firefox on WINDOWS (8dc8a53c-5a96-41e8-9383-e552c7c8f680)
method f id:13 n:1 s:a
Driver: FirefoxDriver: firefox on WINDOWS (8dc8a53c-5a96-41e8-9383-e552c7c8f680)
method f id:13 n:3 s:c
Driver: FirefoxDriver: firefox on WINDOWS (8dc8a53c-5a96-41e8-9383-e552c7c8f680)
method f id:13 n:4 s:d
mfulton26
  • 29,956
  • 6
  • 64
  • 88
  • This approach I have used with my application. But, when I do multithreading with 2 threads i.e one thread in one browser, one thread seems to hang during execution and the other completes. How do I solve for this? – Grishma Oswal Dec 09 '15 at 06:41
  • Strange. Have you made any code changes or does my example here have that problem for you? – mfulton26 Dec 09 '15 at 10:46
  • This example does not have any problem but I have used this scenario with actual application and there I am facing problem – Grishma Oswal Dec 10 '15 at 09:48
  • You might create a new question with a simple example reproducing your issue. We can look at it from there. – mfulton26 Dec 10 '15 at 11:52
  • http://stackoverflow.com/questions/34203048/execute-one-method-in-one-test-tag-in-parallel-in-testng please take a look at my question – Grishma Oswal Dec 10 '15 at 13:23
0

Issue has nothing to with data providers. The problem lies in driver.get("www.google.com");. WebDriver api sends RESTfull request to Selenium server to execute a command. REST services uses http or https protocol for request/response. Hence when we call the url without mentioning the protocol prefix (in this case http), exception is thrown.

Change to :

driver.get("http://www.google.com/");

This will work.

MKay
  • 818
  • 9
  • 32
  • What is an issue you are getting? I copied your java file &`testng.xml` file as it is. It did start all the sessions properly and test is passed for all the 4 parameters. – MKay Dec 04 '15 at 11:31