In this post, we will see how does one make use of TestNG to kick off parallel UI tests using WebDriver.

So lets try doing this with a typical cooking recipe style :)

So here are the ingredients that are required.

  • 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

So without wasting any time lets see how this all blends in.

First lets look at our Factory class. This is a very simplified Factory class that will create instances of WebDriver based upon the browser flavour. I have purposefully kept it simple only for illustration purposes:
Here’s how the Factory class will look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package organized.chaos;
 
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;
    }
}

As you can see its a very simple class with a static method that creates WebDriver instances. The one interesting part to be noted here is that the class has been purposefully given only package visibility [ notice how the keyword "public" is missing from the class declaration ]. One of the many aspects that are involved in designing APIs is “Hide what is not necessary to be visible to your user”. For you to be able to drive a car, you don’t need to know how the piston works or how the fuel injection happens do you :)

Now lets take a look at how our Manager class would look like. The Manager class essentially uses a concept in java called ThreadLocalvariables.

The code would look like below :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package organized.chaos;
 
import org.openqa.selenium.WebDriver;
 
public class LocalDriverManager {
    private static ThreadLocal<WebDriver> webDriver = new ThreadLocal<WebDriver>();
 
    public static WebDriver getDriver() {
        return webDriver.get();
    }
 
    static void setWebDriver(WebDriver driver) {
        webDriver.set(driver);
    }
}

Were you surprised that its such a small class ? :)
So as you can see we basically 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.
You can improvize this by incorporating custom annotations as well and parsing for your custom annotations [ The current implementation that you will see basically spawns a browser irrespective of whether you want to use it or not. That's not a nice idea all the time is it ]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package organized.chaos;
 
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 ingredients, lets take a look at a sample test as well, which is going to use all of this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package organized.chaos;
 
import org.testng.annotations.Test;
 
public class ThreadLocalDemo {
    @Test
    public void testMethod1() {
        invokeBrowser("http://www.ndtv.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 :

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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.chaos.WebDriverListener"></listener>
</listeners>
    <test name="Test">
        <parameter name="browserName" value="firefox"></parameter>
        <classes>
            <class name="organized.chaos.ThreadLocalDemo" />
        </classes>
    </test> <!-- Test -->
</suite> <!-- 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 ]

1
2
3
4
5
6
7
8
9
10
11
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
===============================================

And thus we have managed to leverage TestNG and run WebDriver tests in parallel without having to worry about race conditions or leaving browsers open etc.,

Hope that clears out some of the confusions and helps you get started with WebDriver automation powered by TestNG.

Parallel WebDriver executions using TestNG的更多相关文章

  1. Selenium2(webdriver)入门之TestNG的使用

    一.在Eclipse中安装TestNG 1.打开eclipse-->help-->Install New Software-->Add,输入Name和Location后,点击OK. ...

  2. Selenium2(webdriver)入门之TestNG的安装与简单使用

    上一篇已经搭建好了Eclipse+selenium2的环境,这一篇主要记录下TestNG的使用. 一.在Eclipse中安装TestNG 1.打开eclipse-->help-->Inst ...

  3. 基于WebDriver&TestNG 实现自己的Annotation @TakeScreenshotOnFailure

    相信用过Selenium WebDriver 的朋友都应该知道如何使用WebDriver API实现Take Screenshot的功能. 在这篇文章里,我主要来介绍对failed tests实现 t ...

  4. testng 失败自动截图

    testng执行case failed ,testng Listener会捕获执行失败,如果要实现失败自动截图,需要重写Listener的onTestFailure方法 那么首先新建一个Listene ...

  5. WebDriver - 添加失败截图

    WebDriver失败截图可以通过两种方式实现: 1. Use WebdriverEventListener 第一步:创建自己的WebDriverEventListener 创建自己的WebDrive ...

  6. TestNG实现日志输出

    这里介绍的是TestNG中的Report类来实现简单的log输出这个很简单直接看例子吧 package com.rrx.test; import java.io.IOException; import ...

  7. TestNG实现用例运行失败自动截图(转载)

    转载自:https://blog.csdn.net/galen2016/article/details/70193684 重写Listener的onTestFailure方法 package com. ...

  8. testng失败截图,注解方式调用。

    今天一整天都在研究testng失败截图的方法,参考网上的前辈们的资料,加上自己的理解,终于搞出来了. package com.dengnapianhuahai; /** * 自定义注释 * */ im ...

  9. maven+selenium+java+testng+jenkins自动化测试

    最近在公司搭建了一套基于maven+selenium+java+testng+jenkins的自动化测试框架,免得以后重写记录下 工程目录 pom.xml <project xmlns=&quo ...

随机推荐

  1. java url中文参数乱码问题

    http://www.blogjava.net/jerry-zhaoj/archive/2009/07/16/286993.html 转 JAVA 中URL链接中文参数乱码的处理方法JAVA 中URL ...

  2. Ext学习-基础组件介绍

    1.目标    学习对象获取,组件基础,事件模型以及学习ExtJS中的基础组件的应用. 2.内容   1.对象获取   2.组件原理以及基础   3.事件模型   4.常用组件的介绍 3.学习步骤 1 ...

  3. 如何在Eclipse中配置Tomcat服务器

    之前使用MyEclipse来开发Web应用,可以在MyEclipse中配置服务器,配置完后,直接运行服务器即可,很方便. 最近切换到Eclipse开发环境,发现使用Tomcat的方式不太一样,因此在此 ...

  4. The service ‘xxx’ configured for WCF is not registered with the Autofac container

    最近在使用autofac.wcf时,报如下异常: Exception Details: System.InvalidOperationException: The service 'xxx' conf ...

  5. ios开发小技巧之摇一摇截屏

    1. 监控摇一摇动作 1> 让当前视图控制器成为第一响应者 // 必须先让当前视图控制器成为第一响应者才能响应动作时间 [self becomeFirstResponder]; 2> 实现 ...

  6. 01-03-02-2【Nhibernate (版本3.3.1.4000) 出入江湖】CRUP操作-Save方法的一些问题

    此文由于当时不知道NHibernate的Sava方法不是更新操作,不知道Save就是Add,造成如下荒唐的求证过程,但结论是对的 ,可报废此文,特此声明. NHibernate--Save方法: Cu ...

  7. uuid-不好之处

    数据库中直接存储UUID的坏处: 完全‘随机’的字符串,例如由MD5().SHA1().UUID()产生的.它们产生的每一个新值都会被任意地保存在很大的空间范围内, 这会减慢INSERT及一些SELE ...

  8. Memcache安全配置

    Memcache安全配置 瞌睡龙 · 2014/01/20 17:59 0x00 Memcache简介 Memcache是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash ...

  9. tornado的cookie和secure cookie

    tornado里面有关几个cookie的处理,在web.py文件里. get_cookie, set_cookie普通的设置cookie, clear_cookie, clear_all_cookie ...

  10. Silverlight弹出层(转载)

    ChildWindow为Silverlight中的弹出子窗口 可以在项目新建子窗口文件: 相互传值: //父窗体向子窗体传值,需要在ChildWindow中构造函数进行传值ChildWindowTes ...