TestNG中实现多线程并行执行,可以通过几种方法
- testng.xml中配置
- @Test注解
- @DataProvider注解
testng.xml中配置
testng.xml中可以通过配置Suite、test标签的parallel、thread-count属性来实现
testng.xml中标签属性及含义
name:此套件的名称。这是一个强制性的属性。
parallel:由TestNG 运行不同的线程来运行此套件。
thread-count:使用的线程数,如果启用并行模式(忽略其他方式)
设置方法:
表示:最多起5个线程去同时执行不同的用例
它们的区别是:
- methods
method 级别的多线程测试,每个方法都将采用独立的线程进行测试 - classes
不同标签下的用例可以在不同的线程执行,相同 标签下的用例只能在同一个线程中执行 - tests
test级别的多线程测试,每个标签下的所有方法将在同一个线程中执行,不同的 是在不同的线程来运行的
并行执行测试方法
由每一个独立的线程分别执行各自的测试方法,这种方式能够显著地减少测试执行时间,这是因为当有越多的测试方法被并行执行时,总体测试消耗时间将会越少。
public class ParallelMethodTest {
@BeforeMethod
public void beforeMethod(){
long id = Thread.currentThread().getId();
System.out.println("Before test-method. Thread id is: " + id);
}
@Test
public void testMethodOne(){
long id = Thread.currentThread().getId();
System.out.println("Simple test-method One. Thread id is: " + id);
}
@Test
public void testMethodTwo(){
long id = Thread.currentThread().getId();
System.out.println("Simple test-method One. Thread id is: " + id);
}
@AfterMethod
public void afterMethod(){
long id = Thread.currentThread().getId();
System.out.println("After test-method. Thread id is: " + id);
}
}
直接执行该类,如下图所示,可以看出两个方法都是同一个线程来执行。
我们可以在testng.xml文件中加入如下配置
用TestNG测试套件的方式来执行,执行结果如下图所示,可以看到两个测试方法执行的线程id是不同的,即实现了测试方法的并行执行:
并行执行测试类
同一个测试组件(test execution)中的各个测试类将会在独立的线程中并行地执行
ParallelClassesTest1.java
public class ParallelClassesTest1 {
@BeforeClass
public void beforeClass(){
long id = Thread.currentThread().getId();
System.out.println("Before test-class. Thread id is: " + id);
}
@Test
public void testMethodOne(){
long id = Thread.currentThread().getId();
System.out.println("Simple test-method One. Thread id is: " + id);
}
@Test
public void testMethodTwo(){
long id = Thread.currentThread().getId();
System.out.println("Simple test-method Two. Thread id is: " + id);
}
@AfterClass
public void afterClass(){
long id = Thread.currentThread().getId();
System.out.println("After test-class. Thread id is: " + id);
}
}
ParallelClassesTest2.java
public class ParallelClassesTest2 {
@BeforeClass
public void beforeClass(){
long id = Thread.currentThread().getId();
System.out.println("Before test-class. Thread id is: " + id);
}
@Test
public void testMethodOne(){
long id = Thread.currentThread().getId();
System.out.println("Simple test-method One. Thread id is: " + id);
}
@Test
public void testMethodTwo(){
long id = Thread.currentThread().getId();
System.out.println("Simple test-method Two. Thread id is: " + id);
}
@AfterClass
public void afterClass(){
long id = Thread.currentThread().getId();
System.out.println("After test-class. Thread id is: " + id);
}
}
在testng.xml添加配置如下:
以TestNG测试套件方式运行,运行结果如下,可以看出并行执行两个测试类:
并行执行同一测试套件内的各个测试组件
public class ParallelSuiteTest {
String testName = "";
@BeforeTest
@Parameters("testName")
public void beforeTest(String testName){
this.testName = testName;
long id = Thread.currentThread().getId();
System.out.println("Before test " + testName + ". Thread id is: " + id);
}
@BeforeClass
public void beforeClass() {
long id = Thread.currentThread().getId();
System.out.println("Before test-class " + testName + ". Thread id is: " + id);
}
@Test
public void testMethodOne() {
long id = Thread.currentThread().getId();
System.out.println("Sample test-method " + testName + ". Thread id is: " + id);
}
@AfterClass
public void afterClass() {
long id = Thread.currentThread().getId();
System.out.println("After test-method " + testName + ". Thread id is: " + id);
}
@AfterTest
public void afterTest() {
long id = Thread.currentThread().getId();
System.out.println("After test " + testName + ". Thread id is: " + id);
}
}
这里用到@Parameters参数化
执行结果如下图,可以看出两个测试组件是在两个独立线程中执行的:
@Test注解
TestNG提供了一种灵活的方式来配置需要在多线程环境下运行的测试方法:通过@Test注解的threadPoolSize等属性来实现多线程执行测试方法。当需要对某一个接口进行并发测试时,可以通过这种方法来实现。
@Test(threadPoolSize = 3,invocationCount = 6,timeOut = 1000)
@Test的配置解释
@Test注解通过配置threadPoolSize这个属性来进入多线程模式
threadPoolSize被设为3,这就说明了该测试方法将会在三个不同的线程中同时执行
invocationCount配置的是该测试方法应被执行的总次数
timeOut配置的是每次执行该测试方法所耗费时间的阈值,超过阈值则测试失败
@Test(dataProvider = "test2",threadPoolSize = 5,invocationCount = 10)
如果同时又DataProvider和threadPoolSize参数,则会根据DataProvider中的测试数据数量和invocationCount来确定最终的并发执行次数。
这里的线程池是用于起多个method,而每个method的测试数据由dp提供,如果这边dp里有3组数据,那么实际上10次执行,每次都会调3次接口,这个接口被调用的总次数是10*3=30次。threadPoolSize指定的5个线程中,每个线程单独去调method时,用到的dp如果也是支持并发执行的话,会创建一个新的线程池(dpThreadPool)来并发执行测试数据。具体实例可以通过下面的@DataProvider注解里的实例来进行试验,这里不再演示。
多线程执行测试方法
实例:
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);
}
}
执行结果如下,可以从打印出的日志中看出,该测试方法被执行了多次,而且它的执行次数跟invocationCount所指定的次数相同,且每次执行都是在不同的线程中完成的。当我们需要按照某一固定次数,在多线程环境下运行某些测试方法时,上述特性会很有帮助,因为它避免了我们把整个测试套件都并行执行多次的代价。
@DataProvider注解
在定义数据源的时候,可以通过设置parallel 属性来进行控制器是否并发执行测试,parallel 参数值默认为false,表示使用该数据源的测试方法不能并发执行,将其设置为true,表示使用该数据源的测试方法可以并发执行
并行执行测试方法实例
DataProviderParallelTest.java
public class DataProviderParallelTest {
@Test(dataProvider = "test2")
public void test2(String param1,String param2){
long id = Thread.currentThread().getId();
System.out.println(param1+" "+param2 + " thread id:"+id);
}
@Test(dataProvider = "test1")
public void test1(String param1,String param2){
long id = Thread.currentThread().getId();
System.out.println(param1+" "+param2 + " thread id:"+id);
}
@DataProvider(name = "test2")
public static Object[][] parallel2Test(){
return new Object[][]{
{"dataprovider test2 data1","dataprovider test2 data1"},
{"dataprovider test2 data2","dataprovider test2 data2"}};
}
@DataProvider(name = "test1")
public static Object[][] parallel1Test(){
return new Object[][]{
{"dataprovider test1 data1","dataprovider test1 data1"},
{"dataprovider test1 data2","dataprovider test1 data2"}};
}
}
先来看下不设置DataProvider的parallel参数时,执行情况,执行结果如下:
可以看出一个dp中的多组数据依然是顺序执行
这是如果设置DataProvider的parallel参数为true
@DataProvider(name = "test2",parallel = true)
public static Object[][] parallel2Test(){
return new Object[][]{
{"dataprovider test2 data1","dataprovider test2 data1"},
{"dataprovider test2 data2","dataprovider test2 data2"}};
}
@DataProvider(name = "test1",parallel = true)
public static Object[][] parallel1Test(){
return new Object[][]{
{"dataprovider test1 data1","dataprovider test1 data1"},
{"dataprovider test1 data2","dataprovider test1 data2"}};
}
次数执行结果如下:
可以看出,实现了dataprovider多组测试数据之间的并发,在实际使用过程中可以通过设置DataProvider的并发执行来缩短测试执行时间。
默认情况下,dp并行执行的线程池容量为10,如果要更改并发的数量,也可以在suite tag下指定参数data-provider-thread-count: