Selenium WebDriver Parallel Testing with Selenium Grid 2, Jenkins and TestNG

  • Posted on: 17 November 2013
  • By: Zhijun Chen

Recently I've been working on setting up Webdriver parallel testing on a web app. The following guide will give you a brief walkthrough of the steps and technologies.

* WebDriver (Selenium 2.0)

WebDriver is the primary new feature in Selenium 2.0. It aims to better support dynamic web pages where elements of a page may change without the page itself being reloaded. Full documentation of Webdriver can be found here. A useful design pattern in Webdriver is Page Objects, which documentation can be found here. A Page Object simply models web page areas as objects within the test code. Suppose you have a simple login page as shown in the following code.

<html>
  <head>...</head>
  <body>
    <div>Username: </div>
    <div><input type="text" id="username" /></div>
    <div>Password: </div>
    <div><input type="password" id="password" /></div>
    <div><input type="button" id="login_button" value="Login" /></div>
  </body>
</html>

and you would like to model the elements on that page as Java objects.

/* import statements*/

public class LoginPage {
    private By usernameLocator;
    private By passwordLocator;
    private By loginButtonLocator;
    private final WebDriver driver;

    public LoginPage(WebDriver driver) {
        this.driver = driver;
        initLocators();
    }
    
    private void initLocators() {
       usernameLocator = By.id("username");
       passwordLocator = By.id("password");
       loginButtonLocator = By.id("login_button");
    }
    
    public LoginPage setUsername(String username) {
        WebElement usernameEl = driver.findElement(usernameLocator);
        usernameEl.clear();
        usernameEl.sendKeys(username);
        return this;
    }
    
    public LoginPage setPassword(String password) {
        WebElement passwordEl = driver.findElement(passwordLocator);
        passwordEl.clear();
        passwordEl.sendKeys(password);
        return this;
    }
 
    public HomePage clickLoginButton() {
        driver.findElement(loginButtonLocator).click();
        // Return a new page object representing the destination
        return new HomaPage(driver);
    }
}

The page object class should only be responsible for elements on the page. All assertions should be made inside the tests. A simple login test can then be written as follows.

public void testLogin() {
   LoginPage loginPage = new LoginPage(driver);
   loginPage.setUsername("username");
   loginPage.setPassword("password");
   loginPage.clickLoginButton();
   // some assertions here, e.g. Home page title
}

To improve stability of selenium tests, it is necessary to add WebDriverWait when using WebDriver.findElement method. You also need to make sure that the element is scrolled into view before you interact with it. This can be done through JavascriptExecutor in WebDriver.

((JavascriptExecutor) driver).executeScript("arguments[0]".scrollIntoView(true), element);

It's also helpful to catch StaleElementReferenceException and re-initialize the element.

* Selenium Grid 2

Selenium Grid facilitates Selenium tests by allowing users to:

  • scale by distributing tests on several machines
  • manager multiple environments from a central point, making it easy to run the tests against a vast combination of browsers/operation systems.
  • implement custom hooks to leverage virtual infrastructure for instance.

The following diagram shows the idea of Selenium Grid 2.

 

Here are the steps to set up the grid:

  • Download Selenium Grid standalone server from here.
  • Start Selenium Grid Server using the following command, by default the server will run on port 4444, you can have a look at the grid console on http://localhost:4444/grid/console
java -jar selenium-server-standalone-$version.jar -role hub
  • Register nodes using the following command. Note: For chrome you need to download ChromeDriver, and for IE you need to download IEDriverServer.
java -jar selenium-server-standalone-$version.jar -Dwebdriver.chrome.driver=$chromedriver_location -Dwebdriver.ie.driver=$iedriver_location -role node -hub http://localhost:4444/grid/register

More information can be found here

After setting up the grid, you can now use RemoteWebDriver instead in your Selenium code as follows.

DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setBrowserName("firefox");
capabilities.setPlatform(Platform.MAC);
// disable native event
capabilities.setEnableNativeEvents(false);
RemoteWebDriver driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), capabilities);

When running Selenium tests under multiple browsers in the same machine, there will be browser focus issues. This will lead to test failures. Setting native vent to false will help in this case.

Alternatively, there are some decent Selenium cloud testing platforms available. One of them is Sauce Labs. They allow you to run Selenium tests on the cloud, and test on all possible browser/OS combinations, without having to install them on a local machine. Free plan is also available.

* TestNG

Integrating TestNG into Selenium tests is pretty straightforward. The main advantages of TestNG are parallel tests execution and the use of parameters. Most of the assertions and annotations are quite similar to JUnit. Information can be found here. One way to implement parallel testing in Selenium is to set browser and system as parameters as shown in the following code.

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="TestSuite" parallel="tests" thread-count="5"
  verbose="1">
  <test name="mac-chrome">
    <parameter name="browser" value="chrome" />
    <parameter name="platform" value="mac" />
    <classes>
      <class name="uk.co.zhijun.SeleniumTest" />
    </classes>
  </test>
  <test name="windows-chrome">
    <parameter name="browser" value="chrome" />
    <parameter name="platform" value="windows" />
    <classes>
      <class name="uk.co.zhijun.SeleniumTest" />
    </classes>
  </test>
</suite>

The attribute parallel="tests" allows us to run same tests at the same time but using different parameters. The browser and platform can now pass in to the capability method as follows.

@Parameters({"browser", "platform"})
@BeforeClass
public DesiredCapabilities getCapabilities(String browser, String platform) {
   // code to initialize capabilities
}
* Jenkins

Two useful plugins can be used inside Jenkins to publish Selenium tests report.

It's very easy to set up, you just need to pass in the testng-results.xml file as the input. For Performance plugin, you can even pass in different result xml files generated under different browsers and systems.

Add new comment

Plain text

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.