0

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.stack.imgur.com/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.

2 Answers2

1

There are a few issues with your test code.

  • You have a class level data member WebDriver which gets shared across all @Test methods in the same test class and also across all iterations of a data driven @Test method.
  • You are making use of a @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

Krishnan Mahadevan
  • 14,121
  • 6
  • 34
  • 66
  • thank you very much, this is a very efficace way to execute parallel test, it is actually working. but I still need to group all the tests in multiple tab in 1 chrome window, I tried to add this method in LocalDriverManager, `public static WebDriver getTab() { return webDriver.get().switchTo().newWindow(WindowType.TAB); }` but it opens new window and creates a new tab in each window and then the test get executed. if you can help, I would be very thankful. – moad hamouch Jan 22 '20 at 23:35
  • @moadhamouch - To the best of my knowledge operations that you perform within a `WebDriver` instance are NOT `ThreadSafe`. So you cannot have 3 threads trying to open up 3 tabs on the same Webdriver instance and do different things at the same time. You would need to stick to using 3 different Webdriver instances and then work with them. Its technically equivalent to you working with 3 tabs in the same browser in a manual way. Tab or new window is just a user experience that the browser gives. From an automation standpoint its always equal to 3 new windows. – Krishnan Mahadevan Jan 24 '20 at 08:57
  • @moadhamouch - Please accept my answer if it solves your question. – Krishnan Mahadevan Jan 24 '20 at 08:57
  • I am looking to automate an amazon web page, so I need to stay in one window to avoid re-login for each dataset, it's actually already exist, please have a look at this video; https://youtu.be/TTnrUkQhuFo?t=1833 maybe they used selenium grid or some other advanced frameworks. – moad hamouch Jan 24 '20 at 15:40
0

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>
Muzzamil
  • 2,823
  • 2
  • 11
  • 23
  • Unfortunately, this does not solve a problem, it give me this error message, **org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document** – moad hamouch Jan 19 '20 at 20:00
  • This error is not related to this issue. It was config based issue which solved. This issue is related to element is not attached to DOM so you have to use explicit wait for it to load element – Muzzamil Jan 19 '20 at 20:03
  • You can see solution here for stale element. https://stackoverflow.com/questions/12967541/how-to-avoid-staleelementreferenceexception-in-selenium – Muzzamil Jan 19 '20 at 20:07
  • If your old issue is resolved so don’t forget accept it as answer and upvote to help SO community. It will help people with similar problem in future – Muzzamil Jan 19 '20 at 20:13
  • Hi, maybe i was not precise enough in my question, i just modified it and i redescribed the problem, please revise it and give me your opinion if you can help me, thank you very much. – moad hamouch Jan 20 '20 at 14:06
  • You were getting blank tab as you have mentioned earlier and still image there for old issue. For new issue you raise new question. – Muzzamil Jan 20 '20 at 14:17
  • It is not about single driver if it would be you will not be able to launch 4 tabs. Thread count =3 will handle this thing – Muzzamil Jan 20 '20 at 14:19