TestNG並發執行用例詳解和范例


 

前言

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 (cedric@beust.com)
...

[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 (cedric@beust.com)
...

[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 (cedric@beust.com)
...

[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級並發

此並發方法與前面幾種並發方法類似,只是需要修改parallelinstances即可,為一個實例一個並發,范例如下:

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 (cedric@beust.com)
...

[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 org.uncommons.reportng.HTMLReporter@1d371b2d: 48 ms

如上所示,test1為三個線程,調用六次,超時為1000ms,符合預期;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM