2

This is my class containing Test method f() which I want to execute in parallel. Data provider gives input to test method.

public class DemoTest {
private WebDriver driver;

@Test(dataProvider = "dp")
public void f(Integer n, String s) {
  try {

  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();
  }
}

@BeforeSuite
 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();
  }
 }

@AfterSuite
public void afterMethod() {
  try {
      System.out.println("After method id:"+Thread.currentThread().getId());
  if(driver != null ) {
  driver.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" },

};
}
}

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" data-provider-thread-count="2">
<test name="prelogin">
<classes>
  <class name="com.package.DemoTest"></class>
</classes>
</test>
</suite> 

I want to execute test f() in 2 threads parallely. I get Stale Element Reference exception for one iteration on findElement method. Could anyone tell me what is to be added to this snippet?

Mona
  • 342
  • 1
  • 3
  • 17
Grishma Oswal
  • 303
  • 1
  • 7
  • 22

2 Answers2

1

include name to your data provider,

this should be as follows,

@DataProvider(name = "dp" , 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 your driver.get should be

driver.get("https://www.google.co.in");

and finally coming to your problem.

if there has been any changes to the page after you have initially found the element the webdriver reference will now contain a stale reference. As the page has changed, the element will no longer be where webdriver expects it to be.

To solve your issue, try finding the element each time you need to use it - writing a small method that you can call as and when is a good idea.

private void clickAnElementByLinkText(String id) {
    WebDriverWait wait = new WebDriverWait(driver, 10);
    wait.until(ExpectedConditions.presenceOfElementLocated(By.id(id)));
    driver.findElement(By.id(id)).sendKeys("1234567");
}

@Test(dataProvider = "dp")
public void f(Integer n, String s) {
  try {

  driver.get("https://www.google.co.in");
  clickAnElementByLinkText("lst-ib");
  System.out.println("method f id:"+Thread.currentThread().getId()+" n:"+n+" s:"+s);
  }
  catch(Exception e) {
      e.printStackTrace();
  }
}

now you wont see Stale Element Reference exception

Mona
  • 342
  • 1
  • 3
  • 17
  • Why do I get Stale Element Reference exception only when method is executed in parallel? – Grishma Oswal Dec 04 '15 at 05:30
  • Its not when you execute in parallel, have u tried executing without parallel? Google.com is loaded four times [4 inputs from data provider] and so the element will no longer be where webdriver expects it to be. – Mona Dec 04 '15 at 05:36
  • Yes i have executed without parallel, so i never got this exception – Grishma Oswal Dec 04 '15 at 05:38
  • Is this exception due to using same web driver instance for each thread? – Grishma Oswal Dec 04 '15 at 05:41
  • you've queried about stale element reference exception, it will occur when there has been any changes to the page after you have initially found the element. and so i provided the solution – Mona Dec 04 '15 at 06:00
0

This is caused by using one WebDriver instance by two independent tests. Inside the @BeforeMethod you are creating a new instance by driver= new FirefoxDriver();, but this replaces the field

private WebDriver driver;

by this instance. There is a new instance created by every thread, but only the last one is used - the one that is currently referenced by the private WebDriver driver field. You need to tell every test method to keep the separate WebDriver instance without using it as a class field.

The StaleElementReference exception is thrown when the Webdriver notices that something on the page changed. This happens in your case because another thread is working with the same WebDriver at the time.

Paolo42
  • 182
  • 1
  • 8
  • what to do if i have 10 tests or more running in parallel ? i understand why there is an exception but i do not get how to solve this – Prozorov Nov 24 '20 at 21:12
  • @Prozorov If you want to run these tests in parallel, you have to create a new WebDriver instance for every thread and keep track of them. The original code doesn't work because the new instance always replaces the `private WebDriver driver`, but if you just create ten variables for them - `webdriver1` to `webdriver10` for example - then the problem should be solved. Just remember to use `synchronized` keyword where you need to do something visible from every thread. – Paolo42 Nov 30 '20 at 09:47
  • No , do never create 10 different variables for the same property, that is definitely not a clean code, instead i managed to do it with only 1 driver -> when you run your tests each thread will have its own webdriver, you can specify in pom or gradle file test { systemProperty("junit.jupiter.execution.parallel.enabled", true) systemProperty("junit.jupiter.execution.parallel.mode.default", "CONCURRENT") } – Prozorov Nov 30 '20 at 18:31