Parallel Execution using TestNG

For Parallel execution ,we will be working on 3 different components as below:

  • A Factory class that will create WebDriver instances 
  • A Manager class that can be accessed to retrieve a WebDriver instance
  • A TestNG listener that will be responsible for instantiating the WebDriver instance automatically

First we will create a Factory class which will create and return the desired webdriver object:

























package execution.parallel;
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 take a look at how our Manager class would look like. The Manager class essentially uses a concept in java called ThreadLocal variables.
The code would look like below :









package execution.parallel;
import org.openqa.selenium.WebDriver;
public class LocalDriverManager {
    private static ThreadLocal webDriver = new ThreadLocal();
    public static WebDriver getDriver() {
        return webDriver.get();
    }
    static void setWebDriver(WebDriver driver) {
        webDriver.set(driver);
    }
}
Basically we have a static ThreadLocal variable wherein we are setting webDriver instances and also querying webdriver instances as well.Next comes the TestNG listener. The role of the TestNG listener is to perform “Automatic webdriver instantiation” behind the scenes without your test code even realising it. For this we will make use of IInvokedMethodListener so that the WebDriver gets instantiated right before a Test Method gets invoked and the webDriver gets automatically quit right after the Test method.






















package execution.parallel;
import org.openqa.selenium.WebDriver;
import org.testng.IInvokedMethod;
import org.testng.IInvokedMethodListener;
import org.testng.ITestResult;
public class WebDriverListener implements IInvokedMethodListener {
    @Override
    public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {
        if (method.isTestMethod()) {
            String browserName = method.getTestMethod().getXmlTest().getLocalParameters().get("browserName");
            WebDriver driver = LocalDriverFactory.createInstance(browserName);
            LocalDriverManager.setWebDriver(driver);
        }
    }
    @Override
    public void afterInvocation(IInvokedMethod method, ITestResult testResult) {
        if (method.isTestMethod()) {
            WebDriver driver = LocalDriverManager.getDriver();
            if (driver != null) {
                driver.quit();
            }
        }
    }
}
Now that we have shown all of the components, lets take a look at a sample test as well, which is going to use all of this.
















package execution.parallel;
import org.testng.annotations.Test;
public class ThreadLocalDemo {
    @Test
    public void testMethod1() {
        invokeBrowser("http://www.twitter.com");
    }
    @Test
    public void testMethod2() {
        invokeBrowser("http://www.facebook.com");
    }
    private void invokeBrowser(String url) {
        System.out.println("Thread id = " + Thread.currentThread().getId());
        System.out.println("Hashcode of webDriver instance = " + LocalDriverManager.getDriver().hashCode());
        LocalDriverManager.getDriver().get(url);
    }
}
As you can see its a very simple test class with two test methods. Each of the test methods opens up a different website. I have also add print statements for printing the thread id [yes thats the only reliable way of figuring out if your test method is running in parallel or in sequential mode. If you see unique values for Thread.currentThread().getId() then you can rest assured that TestNG is invoking your test methods in parallel.
We are printing the hashCode() values for the browser to demonstrate the fact that there are unique and different webDriver instances being created for every test method. [ Remember hashCode() value for an object would always be unique ]
Now lets take a look at how our suite file looks like :













xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite" parallel="methods">
<listeners>
<listener class-name="organized.parallel.WebDriverListener"></listener>
</listeners>
    <test name="Test">
        <parameter name="browserName" value="firefox"></parameter>
        <classes>
            <class name="organized.parallel.ThreadLocalDemo" />
        </classes>
    </test>
</suite>
So when you run this test this is how your output would look like [ apart from you seeing two firefox windows popup on your desktop ]





12
[TestNG] Running:
  /githome/PlayGround/testbed/src/test/resources/threadLocalDem.xml
Thread id = 10
Hashcode of webDriver instance = 1921042184
Thread id = 9
Hashcode of webDriver instance = 2017986718
===============================================
Suite
Total tests run: 2, Failures: 0, Skips: 0
===============================================

Comments

Popular posts from this blog

Testing Webservice with SoapUI Having Windows Authentication

Data Driven Testing Using Selenium -WebDriver in Python

How to Re-run Failed Scenarios in Cucumber