Reputation: 11
I'm very new using TestNG and Java programming in general and I have a question in regards to runing testcases with dataprovider in parallel,
in order to run dataprovider test cases in multiple tabs in a single chrome window instead of many windows, I used selenium 4 which allows to open and switch to new tab using the folowing code
driver.switchTo().newWindow(WindowType.TAB);
so, I wrote this code which is successfully run the test cases in sequence mode, but when i run it in parallel mode, it implements each line separately, before moving on to the other line,
consequently, it opens the 3 tabs at the same time, afterwards, it opens the link in the last tab 3 times, and finally it tries to do the 3 searches at the same time, and therefore it cannot execute them.
I find as a result that testNG create a single webdriver to control all the tabs, which is logical to cause the failure of the tests in parallel mode.
https://i.sstatic.net/LV5KS.jpg
This is the code:
package com.mycompany.app;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class testTab {
WebDriver driver;
@BeforeTest
public void beforeTest() {
System.setProperty("webdriver.chrome.driver", "C:\\Browsers drivers\\chromedriver.exe");
driver = new ChromeDriver();
}
@BeforeMethod
public void newTab() {
driver.switchTo().newWindow(WindowType.TAB);
}
@Test(dataProvider = "getData")
public void testAmazon1(String search_word) {
driver.get("https://www.google.com/");
driver.findElement(By.xpath("//input[@name='q']")).sendKeys(search_word + (Keys.RETURN));
}
@DataProvider(parallel=true)
public Object[][] getData() {
Object[][] data = new Object[3][1];
data[0][0] = "bihi";
data[1][0] = "boutfounast";
data[2][0] = "hmad l9rran";
return data;
}
}
This is XML file
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="My Sample Suite" parallel="methods" thread-count="3">
<test name="Amazon test">
<classes>
<class name="com.mycompany.app.testTab"></class>
</classes>
</test>
</suite>
Is there a way to create a webdriver for each test? I am sorry for not being precise and thank you for your answers.
Upvotes: 0
Views: 1705
Reputation: 14746
There are a few issues with your test code.
WebDriver
which gets shared across all @Test
methods in the same test class and also across all iterations of a data driven @Test
method.@BeforeTest
method to initialise your webdriver instance, which means that it gets initialised ONLY once per <test>
tag and if there are any other downstream test classes that extend this test class, they will face NullPointerException
.Is there a way to create a webdriver for each test?
Yes its very much possible. You need to work with ThreadLocal
wherein you instantiate the WebDriver
either in a TestNG listener (or) in a @BeforeMethod
method (because the @BeforeMethod
is guaranteed to run on the same thread as the @Test
)
Here's how you go about doing this.
First create a driver factory that can produce WebDriver
instances for you.
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
class LocalDriverFactory {
static WebDriver createInstance(String browserName) {
WebDriver driver = null;
if (browserName.toLowerCase().contains("firefox")) {
driver = new FirefoxDriver();
return driver;
}
if (browserName.toLowerCase().contains("internet")) {
driver = new InternetExplorerDriver();
return driver;
}
if (browserName.toLowerCase().contains("chrome")) {
driver = new ChromeDriver();
return driver;
}
return driver;
}
}
Now lets create a driver manager, that acts as means to interact with the instantiated webdriver
import org.openqa.selenium.WebDriver;
public class LocalDriverManager {
private static ThreadLocal<WebDriver> webDriver = new ThreadLocal<>();
public static WebDriver getDriver() {
return webDriver.get();
}
static void setWebDriver(WebDriver driver) {
webDriver.set(driver);
}
public static void cleanupDriver() {
webDriver.get().quit();
webDriver.remove();
}
}
Here's how your test class would now look like
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class TestTab {
@BeforeMethod
public void beforeMethod() {
LocalDriverManager.setWebDriver(LocalDriverFactory.createInstance("chrome"));
}
@Test(dataProvider = "dp")
public void testMethod(String searchWord) {
WebDriver driver = LocalDriverManager.getDriver();
driver.get("https://www.google.com/");
driver.findElement(By.xpath("//input[@name='q']")).sendKeys(searchWord + (Keys.RETURN));
}
@DataProvider(name = "dp", parallel = true)
public Object[][] getData() {
return new Object[][] {{"bihi"}, {"boutfounast"}, {"hmad l9rran"}};
}
@AfterMethod
public void afterMethod() {
LocalDriverManager.cleanupDriver();
}
}
I created a detailed blog that explains all of this. You can read more about it here
As an improvisation, I also created a simple maven library called autospawn
that abstracts out all of this browser instantiation and clean up logic from you and lets you work with a webdriver by using a custom annotation.
You can get more information about it from here: https://github.com/RationaleEmotions/autospawn
Upvotes: 1
Reputation: 2881
You need to use dataproviderthreadcount
. The thread-count
values is not required. See details here.
You can use Tesng.xml
as mentioned below :
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="My Sample Suite" parallel="methods" data-provider-thread-count="3">
<test name="Amazon test">
<classes>
<class name="com.mycompany.app.testTab"></class>
</classes>
</test>
</suite>
Upvotes: 0