并行(多線程)技術(shù)在軟件術(shù)語里被定義為軟件、操作系統(tǒng)或者程序可以并行地執(zhí)行另外一段程序中多個部分或者子組件的能力。TestNG允許我們以并行(多線程)的方式來執(zhí)行測試。這意味著基于TestNG測試組件的配置,多個線程可以被同時啟動然后分別執(zhí)行各自的測試方法。相對于傳統(tǒng)的單線程執(zhí)行測試的方式,這種多線程方式擁有很大的優(yōu)勢,主要是它可以減少測試運行時間,并且可以驗證某段代碼在多線程環(huán)境中運行的正確性。
目錄
1.并行執(zhí)行測試的優(yōu)勢
2.如何并行地執(zhí)行測試方法
3.如何并行地執(zhí)行測試類
4.如何并行地執(zhí)行同一測試套件內(nèi)的各個測試組件
5.如何配置需要在多線程環(huán)境中執(zhí)行的測試方法
并行執(zhí)行測試的優(yōu)勢
并行(多線程)執(zhí)行測試可以給用戶帶來很多好處,主要包括以下兩點:
1)減少了執(zhí)行時間:并行測試也意味著多個測試可以在同一時間被同時執(zhí)行,從而減少了整體測試所花費的時間。
2)允許多個線程并行地測試同一個測試組件:有了這個特性,我們能夠?qū)懗鱿鄳?yīng)的測試用例來驗證應(yīng)用程序中包含多線程部分的代碼的正確性。
以上特性被廣泛地應(yīng)用在QA領(lǐng)域的自動化功能測試方面。通過簡單的配置,QA人員可以很輕松地使得他們的測試用例在多個瀏覽器或者操作系統(tǒng)中并行地執(zhí)行。
TestNG提供了三種不同類型的配置方案來實現(xiàn)并行測試。
如何并行地執(zhí)行測試方法
TestNG為我們提供了多種方式來實現(xiàn)并行測試,其中一種是每一個獨立的線程分別執(zhí)行各自的測試方法。這種方式能夠顯著地減少測試執(zhí)行時間,這是因為當(dāng)有越多的測試方法被并行執(zhí)行時,總體測試消耗時間將會越少。
上述測試類包含了兩個測試方法,每個測試方法在執(zhí)行時都會在控制臺中打印出一條信息。每個測試方法以及它們各自的beforeMehod、afterMethod方法都會通過Thread.currentThread.getId()這段代碼打印出執(zhí)行該測試方法的線程的ID。
在項目中新建一個名為methods-test-testng.xml的文件并將下述代碼寫入該文件中。
在Eclipse中選中該文件并且以TestNG測試套件方式運行它。你將會在控制臺中看到以下輸出信息:
注意:上述截圖中的ThreadId可能與你本地控制臺中輸出的ThreadId不同,這是因為ThreadId的值是在程序運行時由JVM動態(tài)指派的。
從上述測試結(jié)果中我們可以很清晰地看出:上述兩個測試方法以及各自相應(yīng)的beforeMethod和afterMethod方法是在兩個獨立的線程中執(zhí)行的。我們可以通過在控制臺中輸出的ThreadId來證明這一點。
如何并行地執(zhí)行測試類
在下個例子中,我們會說明如何并行地執(zhí)行測試類:同一個測試組件(test execution)中的各個測試類將會在獨立的線程中并行地執(zhí)行。
ParallelClassesTestOne.java
ParallelClassesTestTwo.java
在項目中新建一個名為classes-test-testng.xml的文件并將下述代碼寫入該文件中:
在Eclipse中選中該文件并且以TestNG測試套件方式運行它。你將會在控制臺中看到以下輸出信息:
從上述測試結(jié)果中我們可以很清晰地看出:上述兩個測試類以及各自相應(yīng)的beforeClass和afterClass方法是在獨立的兩個線程中執(zhí)行的。我們可以通過在控制臺中輸出的ThreadId來證明這一點。
如何并行地執(zhí)行同一測試套件內(nèi)的各個測試組件
接下來我們會一起學(xué)習(xí)如何并行地執(zhí)行同一個測試套件內(nèi)的各個測試組件,即各個測試組件會分別在獨立的線程中執(zhí)行。
packagecom.howtodoinjava.parallelism;
importorg.testng.annotations.AfterClass;
importorg.testng.annotations.AfterTest;
importorg.testng.annotations.BeforeClass;
importorg.testng.annotations.BeforeTest;
importorg.testng.annotations.Parameters;
importorg.testng.annotations.Test;
publicclassParallelSuiteTest
{
String testName="";
@BeforeTest
@Parameters({"test-name"})
publicvoidbeforeTest(String testName){
this.testName=testName;
longid=Thread.currentThread().getId();
System.out.println("Before test"+testName+".Thread id is:"+id);
}
@BeforeClass
publicvoidbeforeClass(){
longid=Thread.currentThread().getId();
System.out.println("Before test-class"+testName+".Thread id is:"
+id);
}
@Test
publicvoidtestMethodOne(){
longid=Thread.currentThread().getId();
System.out.println("Sample test-method"+testName
+".Thread id is:"+id);
}
@AfterClass
publicvoidafterClass(){
longid=Thread.currentThread().getId();
System.out.println("After test-method"+testName
+".Thread id is:"+id);
}
@AfterTest
publicvoidafterTest(){
longid=Thread.currentThread().getId();
System.out.println("After test"+testName+".Thread id is:"+id);
}
}
在項目中新建一個名為suite-test-testng.xml的文件并將以下代碼寫入該文件中:
<suitename="Test-class Suite"parallel="tests"thread-count="2">
<testname="Test-class test 1">
<parametername="test-name"value="test-method One"/>
<classes>
<classname="com.howtodoinjava.parallelism.ParallelSuiteTest"/>
</classes>
</test>
<testname="Test-class test 2">
<parametername="test-name"value="test-method One"/>
<classes>
<classname="com.howtodoinjava.parallelism.ParallelSuiteTest"/>
</classes>
</test>
</suite>
在Eclipse中選中該文件并且以TestNG測試套件方式運行它。你將會在控制臺中看到以下輸出信息:
Before test Test One.Thread id is:9
Before test Test Two.Thread id is:10
Before test-classTest One.Thread id is:9
Before test-classTest Two.Thread id is:10
Sample test-method Test One.Thread id is:9
Sample test-method Test Two.Thread id is:10
After test-method Test Two.Thread id is:10
After test-method Test One.Thread id is:9
After test Test One.Thread id is:9
After test Test Two.Thread id is:10
從上述測試結(jié)果中我們可以很清晰地看出:上述兩個測試組件是在獨立的兩個線程中分別執(zhí)行的。我們可以通過在控制臺中輸出的ThreadId來證明這一點。
如何配置一個需要在多線程環(huán)境中執(zhí)行的測試方法
之前我們討論了如何并行(多線程)地執(zhí)行測試方法,測試類以及測試組件。TestNG同時也提供了一種靈活的方式來配置需要在多線程環(huán)境下運行的測試方法:只要在該測試方法的@Test注解上配置一些信息,我們能啟用多線程模式。
publicclassIndependentTest
{
@Test(threadPoolSize=3,invocationCount=6,timeOut=1000)
publicvoidtestMethod()
{
Long id=Thread.currentThread().getId();
System.out.println("Test method executing on thread with id:"+id);
}
}
上述測試方法是通過在@Test注解中配置threadPoolSize這個屬性來進(jìn)入多線程模式的。threadPoolSize被設(shè)為3,這說明了該測試方法將會在三個不同的線程中同時執(zhí)行。剩余兩個屬性:invocationCount配置的是該測試方法應(yīng)被執(zhí)行的總次數(shù),timeOut配置的是每次執(zhí)行該測試方法所耗費時間的閾值,超過閾值則測試失敗。
在項目中新建一個名為independent-test-testng.xml的文件,并寫入下述代碼:
<suitename="Independent test Suite">
<testname="Independent test">
<classes>
<classname="com.howtodoinjava.parallelism.IndependentTest"/>
</classes>
</test>
</suite>
在Eclipse中選中該文件并以TestNG測試套件方式運行。你將會在控制臺中看到以下輸出信息
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
在這里,我們可以看出該測試方法被執(zhí)行了多次,而且它的執(zhí)行次數(shù)跟invocationCount所指定的次數(shù)相同。而且從輸出信息中,我們也可以很清晰地看到該測試方法每次執(zhí)行都是在不同的線程中完成的。當(dāng)我們需要按照某一固定次數(shù),在多線程環(huán)境下運行某些測試方法時,上述特性會很有幫助,因為它避免了我們把整個測試套件都并行執(zhí)行多次的代價。