TestNG提供了一种灵活的方式来配置并行测试。可以通过在测试方法的@Test注解上配置一些信息来启用多线程模式。这样,基于TestNG测试组件的配置,多个线程可以同时启动并分别执行各自的测试方法。相对于传统的单线程执行测试的方式,多线程方式可以减少测试运行时间,并且可以验证某段代码在多线程环境中的正确性。

并行测试的优势

并行(多线程)执行测试可以给用户带来很多好处,主要包括以下两点:
(1)提高测试效率:多个测试用例在同一时间内同时执行,对单线程执行测试用例而言,可减少测试执行时间,提高测试效率。
(2)并行执行同一个测试组件中的测试用例,该特性可验证验证应用程序中包含多线程部分的代码的正确性。
以上特性被广泛地应用在自动化功能测试方面。通过简单的配置,测试人员可在多个浏览器或者操作系统中并行执行测试用例。

并行执行测试方法

每个线程独立执行各自的测试方法,这种方式能减少测试执行时间,当有越多的测试方法被并行执行时,总体测试消耗时间将会越少

package com.newbeeTest;

import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class TestNgTest {
    @BeforeMethod
    public void beforeMethod(){
        System.out.println("this is beforeMethod "+Thread.currentThread().getId());
    }
    @Test
    public void testMethodOne(){
        System.out.println("this is FirstMethod "+Thread.currentThread().getId());
    }
    @Test
    public void testMethodTwo(){
        System.out.println("this is SecondMethod "+Thread.currentThread().getId());
    }
    @AfterMethod
    public void afterMethod(){
        System.out.println("this is afterMethod "+Thread.currentThread().getId());
    }
}

测试套件中组织如下:

<?xml version="1.0" encoding="utf-8" ?>
<suite name="testMethodSuite"  parallel="methods" thread-count="2">
    <test name="TestMethod" group-by-instances="true">
        <classes>
            <class name="com.newbeeTest.TestNgTest"></class>
        </classes>
    </test>
</suite>

执行结果

this is beforeMethod 11
this is beforeMethod 12
this is FirstMethod 11
this is SecondMethod 12
this is afterMethod 12
this is afterMethod 11

并行执行测试类

同一个测试组件(test execution)中的各个测试类将会在独立的线程中并行地执行
FirstClassTest

public class FirstClassTest {
    @BeforeClass
    public void beforeClass() {
        System.out.println("This is BeforeClass. Thread id is: " + Thread.currentThread().getId());
    }

    @Test
    public void testMethodOne() {
        System.out.println("This is FirstMethod. Thread id is: " + Thread.currentThread().getId());
    }

    @Test
    public void testMethodTwo() {
        System.out.println("This is SecondMethod. Thread id is: " + Thread.currentThread().getId());
    }

    @AfterClass
    public void afterClass() {
        System.out.println("This is AfterClass. Thread id is: " + Thread.currentThread().getId());
    }
}

SecondClassTest

public class SecondClassTest {
    @BeforeClass
    public void beforeClass() {
        System.out.println("This is BeforeClass. Thread id is: " + Thread.currentThread().getId());
    }

    @Test
    public void testMethodOne() {
        System.out.println("This is FirstMethod. Thread id is: " + Thread.currentThread().getId());
    }

    @Test
    public void testMethodTwo() {
        System.out.println("This is SecondMethod. Thread id is: " + Thread.currentThread().getId());
    }

    @AfterClass
    public void afterClass() {
        System.out.println("This is AfterClass. Thread id is: " + Thread.currentThread().getId());
    }
}

测试套件组织如下:

<?xml version="1.0" encoding="utf-8" ?>
<suite name="testClassesSuite"  parallel="classes" thread-count="2">
    <test name="TestMethod">
        <classes>
            <class name="com.newbeeTest.FirstClassTest"></class>
            <class name="com.newbeeTest.SecondClassTest"></class>
        </classes>
    </test>
</suite>

执行结果

This is BeforeClass. Thread id is: 11
This is BeforeClass. Thread id is: 12
This is FirstMethod. Thread id is: 11
This is FirstMethod. Thread id is: 12
This is SecondMethod. Thread id is: 11
This is AfterClass. Thread id is: 11
This is SecondMethod. Thread id is: 12
This is AfterClass. Thread id is: 12

并行执行同一测试套件内的各个测试组件

各个测试组件分别在独立的线程中执行

public class ParallelSuiteTest {
    String testName = "";
    @BeforeTest
    @Parameters({ "test-name" })
    public void beforeTest(String testName){
        this.testName = testName;
        System.out.println("the beforeTest is Before"+ testName +". Thread id is " + Thread.currentThread().getId());
    }
    @BeforeClass
    public void beforeClass(){
        System.out.println("the beforeClass is BeforeClass"+ testName +". Thread id is " + Thread.currentThread().getId());
    }
    @Test
    public void testMethodOne(){
        System.out.println("the test is "+ testName +". Thread id is " +Thread.currentThread().getId());
    }
    @Test
    public void testMethodTwo(){
        System.out.println("the test is "+ testName +". Thread id is " +Thread.currentThread().getId());
    }
    @AfterClass
    public void afterClass(){
        System.out.println("the afterClass is AfterClass"+ testName +". Thread id is " +Thread.currentThread().getId());
    }
    @AfterTest
    public void afterTest(){
        System.out.println("the afterTest is After"+ testName +". Thread id is " +Thread.currentThread().getId());
    }
}

测试套件组织如下:

<?xml version="1.0" encoding="utf-8" ?>
<suite name="Test-class Suite" parallel="tests" thread-count="2">
    <test name="Test-class test One">
        <parameter name="test-name" value="Test One" />
        <classes>
            <class name="com.newbeeTest.ParallelSuiteTest" />
        </classes>
    </test>
    <test name="Test-class test Two">
        <parameter name="test-name" value="test Two" />
        <classes>
            <class name="com.newbeeTest.ParallelSuiteTest" />
        </classes>
    </test>
</suite>

执行结果如下:

the beforeTest is Beforetest Two. Thread id is 12
the beforeTest is BeforeTest One. Thread id is 11
the beforeClass is BeforeClassTest One. Thread id is 11
the beforeClass is BeforeClasstest Two. Thread id is 12
the test is Test One. Thread id is 11
the test is test Two. Thread id is 12
the test is Test One. Thread id is 11
the afterClass is AfterClassTest One. Thread id is 11
the test is test Two. Thread id is 12
the afterClass is AfterClasstest Two. Thread id is 12
the afterTest is Aftertest Two. Thread id is 12
the afterTest is AfterTest One. Thread id is 11

在多线程环境中执行的测试方法

TestNG提供了一种灵活的方式来配置需要在多线程环境下运行的测试方法:在该测试方法的@Test注解上配置一些信息,即可启用多线程模式

public class IndependentTest
{
    @Test(threadPoolSize = 3, invocationCount = 6, timeOut = 1000)
    public void testMethod()
    {
        Long id = Thread.currentThread().getId();
        System.out.println("Test method executing on thread with id: " + id);
    }
}

threadPoolSize:当前方法的线程池大小。方法将被多线程调用, 次数由 invocationcount 参数指定
invocationCount:当前方法被调用的次数
timeOut:当前方法容许花费的最大时间,单位毫秒
测试套件组织如下:

<suite name="Independent test Suite" >
 <test name="Independent test">
   <classes>
    <class name="com.howtodoinjava.parallelism.IndependentTest" />
   </classes>
 </test>
</suite>

执行结果为

Test method executing on thread with id: 11
Test method executing on thread with id: 10
Test method executing on thread with id: 9
Test method executing on thread with id: 11
Test method executing on thread with id: 11
Test method executing on thread with id: 10