【TestNG】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 ([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
[Tes