前言
TestNG有多种并发方式支持,方法的并发,class级的并发,test级的并发等;
根据实际应用可以灵活的配置和使用,下面分别对几种并发方法进行说明:
一、方法级并发
方法级并发即method级并发,此种并发方式需要将xml中的suite
标签的parallel
属性设置为methods
并添加属性thread-count
并设置其值,其会将所有的方法按照设定的并发数进行并发,譬如总共有4个测试用例,并发数设置为3,则会开三个线程,那么必然会有两个用例是在同一个线程内的,跟用例在哪个class内没关系,范例如下:
测试用例类一ThreadTest.java
:
package com.demo.test.testng; import org.testng.annotations.Test; public class ThreadTest { @Test() public void test1() { long id = Thread.currentThread().getId(); System.out.println("test1-1 thread id:"+id); } @Test public void test2() { long id = Thread.currentThread().getId(); System.out.println("test1-2 thread id:"+id); } }
测试用例类二ThreadTest2
:
package com.demo.test.testng; import org.testng.annotations.Test; public class ThreadTest2 { @Test() public void test1() { long id = Thread.currentThread().getId(); System.out.println("test2-1 thread id:"+id); } @Test public void test2() { long id = Thread.currentThread().getId(); System.out.println("test2-2 thread id:"+id); } }
xml设置并发数为3
,并发类型为methods
:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="threadSuite" parallel="methods" thread-count="3"> <test name="Test"> <classes> <class name="com.demo.test.testng.ThreadTest"/> <class name="com.demo.test.testng.ThreadTest2"/> </classes> </test> <!-- Test --> </suite> <!-- Suite -->
执行结果如下:
[RemoteTestNG] detected TestNG version 6.10.0 [TestNG] Running: D:\software\workspace\testng\src\main\java\com\demo\test\testCase\ThreadTestXml.xml test1-1 thread id:12 test2-1 thread id:14 test1-2 thread id:13 test2-2 thread id:13 =============================================== threadSuite Total tests run: 4, Failures: 0, Skips: 0 ===============================================
如上图所示,确实是开了三个线程,且有两个相同线程号的用例并非同一个测试类;
二、class级并发
此并发方式需要将xml中的suite
标签内的属性parallel
属性设置为classes
,且添加属性thread-count
并设置其值即可实现class级别并发,其会一个class内的所有方法放在一个线程内,根据线程数设置和总的class数来分配线程,譬如如果设置线程数为3
,而class
数目为2
,则会开两个线程来分别运行两个class
,而如果设置线程数为3
,且class数目为4
则将会有两个class
在一个线程内,如下为一个简单的范例:
两个用例类如下:ThreadTest.java
package com.demo.test.testng; import org.testng.annotations.Test; public class ThreadTest { @Test() public void test1() { long id = Thread.currentThread().getId(); System.out.println("test1-1 thread id:"+id); } @Test public void test2() { long id = Thread.currentThread().getId(); System.out.println("test1-2 thread id:"+id); } }
ThreadTest2.java
package com.demo.test.testng; import org.testng.annotations.Test; public class ThreadTest2 { @Test() public void test1() { long id = Thread.currentThread().getId(); System.out.println("test2-1 thread id:"+id); } @Test public void test2() { long id = Thread.currentThread().getId(); System.out.println("test2-2 thread id:"+id); } }
测试xml如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="threadSuite" parallel="classes" thread-count="3" verbose="2"> <test name="Test"> <classes> <class name="com.demo.test.testng.ThreadTest"/> <class name="com.demo.test.testng.ThreadTest2"/> </classes> </test> <!-- Test --> </suite> <!-- Suite -->
运行结果:
[RemoteTestNG] detected TestNG version 6.10.0 ... ... TestNG 6.10 by Cédric Beust ([email protected]) ... [TestNG] Running: D:\software\workspace\testng\src\main\java\com\demo\test\testCase\ThreadTestXml.xml [TestRunner] Starting executor for test Test with time out:2147483647 milliseconds. test2-1 thread id:13 test1-1 thread id:12 test2-2 thread id:13 test1-2 thread id:12 PASSED: test1 PASSED: test1 PASSED: test2 PASSED: test2 =============================================== Test Tests run: 4, Failures: 0, Skips: 0 ===============================================
可以看到两个类分别开了一个线程,同一个类中的用例在同一个线程内,符合预期;
那么如果有一个suite下有多个test
,这个并发设置会否将所有的test都计算在呢?来试一下,新添加一个测试用例Depend1.java
:
package com.demo.test.testng; import org.testng.Assert; import org.testng.annotations.Test; public class DependTest1 { @Test(groups= {"dependGroup1"}) public void dependTest1() { System.out.println("dependTest1"); } @Test(groups= {"dependGroup1"}) public void dependTest2() { System.out.println("dependTest2"); } @Test(groups="dependGroup2") public void dependTest4() { System.out.println("dependTest4"); Assert.assertFalse(false); } }
修改xml为如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="threadSuite" parallel="classes" thread-count="2" verbose="2"> <test name="Test1"> <classes> <class name="com.demo.test.testng.ThreadTest"/> <class name="com.demo.test.testng.ThreadTest2"/> </classes> </test> <!-- Test --> <test name="test2"> <classes> <class name="com.demo.test.testng.DependTest1"> </class></classes> </test> </suite> <!-- Suite -->
再次运行结果如下:
[RemoteTestNG] detected TestNG version 6.10.0 ... ... TestNG 6.10 by Cédric Beust ([email protected]) ... [TestNG] Running: D:\software\workspace\testng\src\main\java\com\demo\test\testCase\ThreadTestXml.xml [TestRunner] Starting executor for test Test1 with time out:2147483647 milliseconds. test2-1 thread id:13 test1-1 thread id:12 test2-2 thread id:13 test1-2 thread id:12 PASSED: test1 PASSED: test1 PASSED: test2 PASSED: test2 =============================================== Test1 Tests run: 4, Failures: 0, Skips: 0 =============================================== [TestRunner] Starting executor for test test2 with time out:2147483647 milliseconds. dependTest1 dependTest2 dependTest4 PASSED: dependTest1 PASSED: dependTest2 PASSED: dependTest4 =============================================== test2 Tests run: 3, Failures: 0, Skips: 0 =============================================== =============================================== threadSuite Total tests run: 7, Failures: 0, Skips: 0 ===============================================
可以看到是先运行test1
(内含两个测试类),开了两个线程,而后再运行test2
(内含一个测试类),开了一个线程,而这两个test内的三个class是并没有放在一起运行的;
故这种并发设置是根据每个test
标签生效的;
三、test级并发
test级并发为将xml中每个test标签下的用例放在一个线程内并根据并发数和tet数目开线程的并发方法,需要将xml中的suite
标签内的属性parallel
属性设置为tests
,且添加属性thread-count
并设置其值即可,譬如有一个suite
下有两个test
且并发数设置为2
,那么就会开两个线程,每个线程都包含一个test
,范例如下:ThreadTest.java
:
package com.demo.test.testng; import org.testng.annotations.Test; public class ThreadTest { @Test() public void test1() { long id = Thread.currentThread().getId(); System.out.println("test1-1 thread id:"+id); } @Test public void test2() { long id = Thread.currentThread().getId(); System.out.println("test1-2 thread id:"+id); } }
ThreadTest2.java
:
package com.demo.test.testng; import org.testng.annotations.Test; public class ThreadTest2 { @Test() public void test1() { long id = Thread.currentThread().getId(); System.out.println("test2-1 thread id:"+id); } @Test public void test2() { long id = Thread.currentThread().getId(); System.out.println("test2-2 thread id:"+id); } }
修改DependTest1.java
:
package com.demo.test.testng; import org.testng.Assert; import org.testng.annotations.Test; public class DependTest1 { @Test(groups= {"dependGroup1"}) public void dependTest1() { long id = Thread.currentThread().getId(); System.out.println("dependTest1 id:"+id); } @Test(groups= {"dependGroup1"}) public void dependTest2() { long id = Thread.currentThread().getId(); System.out.println("dependTest2 id:"+id); } @Test(groups="dependGroup2") public void dependTest4() { long id = Thread.currentThread().getId(); System.out.println("dependTest4 id:"+id); Assert.assertFalse(false); } }
xml设置如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="threadSuite" parallel="tests" thread-count="2" verbose="2"> <test name="Test1"> <classes> <class name="com.demo.test.testng.ThreadTest"/> <class name="com.demo.test.testng.ThreadTest2"/> </classes> </test> <!-- Test --> <test name="test2"> <classes> <class name="com.demo.test.testng.DependTest1"> </class></classes> </test> </suite> <!-- Suite -->
运行结果:
[RemoteTestNG] detected TestNG version 6.10.0 ... ... TestNG 6.10 by Cédric Beust ([email protected]) ... [TestNG] Running: D:\software\workspace\testng\src\main\java\com\demo\test\testCase\ThreadTestXml.xml [ThreadUtil] Starting executor timeOut:2147483647ms workers:2 threadPoolSize:2 dependTest1 id:13 test1-1 thread id:12 test1-2 thread id:12 dependTest2 id:13 test2-1 thread id:12 dependTest4 id:13 test2-2 thread id:12 PASSED: test1 PASSED: test2 PASSED: test1 PASSED: test2 =============================================== Test1 Tests run: 4, Failures: 0, Skips: 0 =============================================== PASSED: dependTest1 PASSED: dependTest2 PASSED: dependTest4 =============================================== test2 Tests run: 3, Failures: 0, Skips: 0 =============================================== =============================================== threadSuite Total tests run: 7, Failures: 0, Skips: 0 ===============================================
可见两个test是开了两个线程运行的,且同一个test内的用例都在同一个线程内;
四、instances级并发
此并发方法与前面几种并发方法类似,只是需要修改parallel
为instances
即可,为一个实例一个并发,范例如下:
package com.demo.test.testng; import java.util.ArrayList; import java.util.List; import org.testng.annotations.Factory; import org.testng.annotations.Test; public class FactoryTest { private String host; private int port; public FactoryTest(String host, int port) { this.host=host; this.port=port; } @Test public void login() { long id = Thread.currentThread().getId(); System.out.println("login, host:"+host+";port"+port+";id:"+id); } @Test(dependsOnMethods="login") public void logout() { long id = Thread.currentThread().getId(); System.out.println("logout, host:"+host+";port"+port+";id:"+id); } @Factory public static Object[] create() { List<FactoryTest> list = new ArrayList<FactoryTest>(); list.add(new FactoryTest("10.10.10.1", 8080)); list.add(new FactoryTest("10.10.10.2", 8080)); return list.toArray(); } }
xml如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="threadSuite" parallel="instances" thread-count="4" verbose="2"> <test name="Test1"> <classes> <class name="com.demo.test.testng.FactoryTest" /> </classes> </test> </suite> <!-- Suite -->
运行结果如下:
[RemoteTestNG] detected TestNG version 6.10.0 ... ... TestNG 6.10 by Cédric Beust ([email protected]) ... [TestNG] Running: D:\software\workspace\testng\src\main\java\com\demo\test\testCase\ThreadTestXml.xml [TestRunner] Starting executor for test Test1 with time out:2147483647 milliseconds. login, host:10.10.10.1;port8080;id:12 login, host:10.10.10.2;port8080;id:13 logout, host:10.10.10.1;port8080;id:14 logout, host:10.10.10.2;port8080;id:15 PASSED: login PASSED: login PASSED: logout PASSED: logout =============================================== Test1 Tests run: 4, Failures: 0, Skips: 0 =============================================== =============================================== threadSuite Total tests run: 4, Failures: 0, Skips: 0 ===============================================
如上log可知,两个用例,两组参数,共四条用例开了四个线程,每个用例都是一个实例;
如果是没有@Factory
注解的普通用例,则没效果。
五、测试用例级并发
此级并发可以直接在用例内设置,如下为一个范例:
package com.demo.test.testng; import org.testng.annotations.Test; public class ThreadTest { @Test(threadPoolSize = 3, invocationCount = 6, timeOut = 1000) public void test1() { long id = Thread.currentThread().getId(); System.out.println("test1-1 thread id:"+id); } @Test public void test2() { long id = Thread.currentThread().getId(); System.out.println("test1-2 thread id:"+id); } }
如上图代码所示,test1
设置线程数为3,调用次数为6,超时时间为1000ms,运行结果如下:
[RemoteTestNG] detected TestNG version 6.10.0 [TestNG] Running: C:\Users\dufei\AppData\Local\Temp\testng-eclipse--1263110808\testng-customsuite.xml [ThreadUtil] Starting executor timeOut:1000ms workers:6 threadPoolSize:3 test1-1 thread id:13 test1-1 thread id:14 test1-1 thread id:12 test1-1 thread id:14 test1-1 thread id:13 test1-1 thread id:12 test1-2 thread id:1 PASSED: test1 PASSED: test1 PASSED: test1 PASSED: test1 PASSED: test1 PASSED: test1 PASSED: test2 =============================================== Default test Tests run: 7, Failures: 0, Skips: 0 =============================================== =============================================== Default suite Total tests run: 7, Failures: 0, Skips: 0 =============================================== [TestNG] Time taken by [email protected]: 48 ms
如上所示,test1
为三个线程,调用六次,超时为1000ms,符合预期;