TestNG 介紹
TestNG 也是一套測試框架,表示下一代(next genaration),它的靈感來源於 Junit(.java 的單元測試框架)和 Nunit(.net 的單元測試框架),但是它又在此基礎上引入了新的東西,使得它更加強大。
TestNG 是一個設計用來簡化廣泛的測試需求的測試框架,從單元測試(隔離測試一個類)到集成測試(測試由有多個類多個包甚至多個外部框架組成的整個系統,例如應用服務器)。
TestNG 的優點:
- 漂亮的 HTML 格式測試報告
- 支持並發測試
- 參數化測試更簡單
- 支持輸出日志
- 支持更多功能的注解
- 不僅支持單元測試,還支持集成測試
TestNG 使用步驟:
- 編寫測試代碼邏輯
- 插入 TestNG 注解標簽
- 配置 Testng.xml 文件,設定測試類、測試方法、測試分組等執行信息
- 運行 TestNG 的測試程序(java 文件或 xml 配置文件均可右鍵運行)
Maven TestNG 依賴:
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.10</version>
<scope>test</scope>
</dependency>
TestNG 常用注解
TestNG 支持多種注解,可以進行各種組合,如下進行簡單的說明:
注解 | 描述 |
---|---|
@BeforeSuite | 在該套件的所有測試都運行在注釋的方法之前。僅運行一次 |
@AfterSuite | 在該套件的所有測試都運行在注釋方法之后。僅運行一次 |
@BeforeClass | 在調用當前類的第一個測試方法之前運行。注釋方法僅運行一次 |
@AfterClass | 在調用當前類的第一個測試方法之后運行。注釋方法僅運行一次 |
@BeforeTest | 注釋的方法將在屬於 test 標簽內的類的所有測試方法運行之前運行 |
@AfterTest | 注釋的方法將在屬於 test 標簽內的類的所有測試方法運行之后運行 |
@BeforeGroups | 配置方法將在之前運行組列表。 此方法保證在調用屬於這些組中的任何一個的第一個測試方法之前不久運行 |
@AfterGroups | 此配置方法將在之后運行組列表。 該方法保證在調用屬於任何這些組的最后一個測試方法之后不久運行 |
@BeforeMethod | 注釋方法將在每個測試方法之前運行 |
@AfterMethod | 注釋方法將在每個測試方法之后運行 |
@DataProvider | 標記一種方法來提供測試方法的數據。 注釋方法必須返回一個 Object[][],其中每個 Object[] 可以被分配給測試方法的參數列表; 要從該 DataProvider 接收數據的 @Test 方法需要使用與此注釋名稱相等的 dataProvider 名稱 |
@Factory | 將一個方法標記為工廠,返回TestNG將被用作測試類的對象。 該方法必須返回 Object[] |
@Listeners | 定義測試類上的偵聽器 |
@Parameters | 描述如何將參數傳遞給 @Test 方法 |
@Test | 將類或方法標記為測試的一部分。 若此標記若放在類上,則該類所有公共方法都將被作為測試方法 |
TestNG 的執行順序如下:
@BeforeSuite > @BeforeTest > @BeforeMethod > @Test > @AfterMethod > @AfterTest > @AfterSuite
TestNG 常用斷言
硬斷言
在 TestNg 中,Assert 類為硬斷言,里面有多個靜態方法被稱為硬斷言。特點就是,如果腳本運行斷言失敗,馬上停止運行,后面代碼將不會被執行。
TestNG 中提供了多個形如 assert*() 的方法,主要是匹配不同的數據類型和集合類及其他對象操作。
方法名 | 說明 |
---|---|
assertEquals(actual, expected) | 查看兩個對象是否相等。類似於字符串比較使用的 equals() 方法 |
assertNotEquals(actual, expected) | 查看兩個對象是否不相等 |
assertNull(object) | 查看對象是否為空 |
assertNotNull(object) | 查看對象是否不為空 |
assertSame(actual, expected) | 查看兩個對象的引用是否相等。類似於使用“=-”比較兩個對象 |
assertNotSame(actual, expected) | 查看兩個對象的引用是否不相等。類似於使用“!=”比較兩個對象 |
assertTrue(condition) | 查看運行結果是否為 true |
assertFalse(condition) | 查看運行結果是否為 false |
assertArrayEquals(actual.expected) | 查看兩個數組是否相等 |
fail() | 讓測試失敗 |
軟斷言
在 TestNg 中,SoftAssert 類為軟斷言。特點是如果運行斷言失敗,不會停止運行,會繼續執行這個斷言下的其他語句或者斷言,不影響其他斷言的運行。
使用說明:assertAll() 一定要放在該測試類的最后一個斷言后面,軟斷言的類叫 SoftAssert.java,這個類是需要創建實例對象的,才能調用相關實例方法進行軟斷言。
示例:
import org.testng.annotations.Test;
import org.testng.asserts.SoftAssert;
public class TestSoftAssert {
@Test
public void testSoftAssert(){
System.out.println("腳本執行開始");
// 實例化 SoftAssert
SoftAssert assertion = new SoftAssert();
assertion.assertEquals(5, 6, "我倆不是一樣大");
System.out.println("腳本執行結束");
System.out.println("我是觀望,到這會不會執行的");
// 這個必須放到最后,沒什么可說的
assertion.assertAll();
}
}
執行結果:
...
腳本執行開始
腳本執行結束
我是觀望,到這會不會執行的
java.lang.AssertionError: The following asserts failed:
我倆不是一樣大
Expected :6
Actual :5
...
通過執行結果發現,在斷言 5 和 6 相等的這行代碼后,還有其他的語句。如果這里采用的是硬斷言,那么后面的"腳本執行結束"和"我是觀望,到這會不會執行的"是不會輸出的,這就是 SoftAssert 的特點。
group:分組
- 把在一個 Test 標簽內的中所有類方法再進行分組。在運行時,一個組的方法會一起運行,然后再運行下一個組的方法;
- 分組的最小維度為方法,當把帶分組的 @Test(groups="groupName") 注解對類使用時,這個測試類中的所有方法都屬於這同一個組;
- 一個方法也可以同時屬於多個組,如 @Test(groups={"groupName1", "groupName2"}),那么每組運行時這個方法都會被執行一次;
- 同一個組里的方法類,如果分別屬於兩個不同的測試用例(\Test 標簽)內,那么它們其實可以算兩個組,它們會在每個測試用例分別運行,而不會合在一起運行。
示例:
import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
public class GroupTest {
@BeforeGroups(groups="server")
public void beforeGroupsOnServer() {
System.out.println("服務端組運行前執行的方法。。。");
}
@BeforeGroups(groups="client")
public void beforeGroupsOnClient() {
System.out.println("客戶端組運行前執行的方法。。。");
}
@Test(groups="server")
public void test1() {
System.out.println("server test1 run ....");
}
@Test(groups="server")
public void test2() {
System.out.println("server test2 run ....");
}
@Test(groups="client")
public void test3() {
System.out.println("client test3 run ....");
}
@Test(groups="client")
public void test4() {
System.out.println("client test4 run ....");
}
@AfterGroups(groups="server")
public void afterGroupsOnServer() {
System.out.println("服務端組運行之后執行的方法。。。");
}
@AfterGroups(groups="client")
public void afterGroupsOnClient() {
System.out.println("客戶端組運行之后執行的方法。。。");
}
}
執行結果:
服務端組運行前執行的方法。。。
server test1 run ....
server test2 run ....
服務端組運行之后執行的方法。。。
客戶端組運行前執行的方法。。。
client test3 run ....
client test4 run ....
客戶端組運行之后執行的方法。。。
enable:忽略執行
默認是 true , 如果設置為 false ,則表示在運行時不會執行這個測試方法。
示例:
import org.testng.annotations.Test;
public class EnableTest {
@Test
public void ignore1() {
System.out.println("ignore1 run ...");
}
@Test(enabled = false)
public void ignore2() {
System.out.println("ignore2 run ...");
}
@Test
public void ignore3() {
System.out.println("ignore3 run ...");
}
}
執行結果:
ignore1 run ...
ignore3 run ...
expectedExeption:預期異常
示例:@Test(expectedExceptions=ClassName.class) 表示若測試代碼拋出了預期想要的異常類(ClassName),則測試通過,沒有異常則算測試不通過。
expectedExceptions 的值也可以是一個數組,如:@Test(expectedExceptions={ClassName.class, ClassName2.class, ...})
示例:
import org.testng.annotations.Test;
public class ExpectedException {
/**
* 運行時異常,我們期望返回一個運行時異常,這條用例才是正確的。
*/
@Test(expectedExceptions = RuntimeException.class, enabled = false)
public void runTimeExceptionFailed() {
System.out.println("沒有拋出異常,這條用例不通過!");
}
/**
* 結果拋出了一個運行時異常,和我們的期望一致,測試通過。
*/
@Test(expectedExceptions = RuntimeException.class)
public void runTimeExceptionSuccess() {
System.out.println("程序拋出了運行時異常,測試用例通過!");
throw new RuntimeException();
}
}
執行結果:
程序拋出了運行時異常,測試用例通過!
dependsOnMethods:依賴方法
在被依賴的方法運行完成之后運行當前方法,如果依賴方法測試不通過,那么當前方法也不會繼續運行。
依賴的方法可以有多個,例:@Test(dependsOnMethods={"methodName1", "methodName2"})
示例:
import org.testng.annotations.Test;
/**
*
*/
public class DependTest {
@Test
public void test1() {
System.out.println("test1 run ...");
}
/**
* test2 運行時,需要依賴 test1 的運行
* 如果 test1 運行失敗,會直接忽略 test2,test2 就不會執行了
*/
@Test(dependsOnMethods = {"test1"})
public void test2() {
System.out.println("test2 run ...");
}
}
執行結果:
test1 run ...
test2 run ...
屬性總結
屬性名 | 描述 |
---|---|
alwaysRun | 設置為 true 時,無論什么情況都會運行 |
dataProvider | 數據提供者的名稱 |
dataProviderClass | 如果未指定,將在當前測試方法的類或其父類之一上查找數據提供者; 如果指定了此屬性,則數據提供者方法在指定的類上必須是靜態的 |
dependsOnGroups | 依賴的組列表 |
dependsOnMethods | 依賴的方法列表 |
description | 說明 |
enabled | 默認為true,設置為 false 時失效 |
expectedExceptions | 預期測試方法將引發的異常列表。 如果未引發任何異常或與該列表中的異常不同,則此測試將標記為失敗 |
groups | 所屬組 |
invocationCount | 調用次數 |
invocationTimeOut | 所有 invocationCount 的累積超時時間。 注意:如果未指定 nvocationCount,則將忽略此屬性 |
priority | 此測試方法的優先級 |
successPercentage | 該方法預期成功的百分比 |
singleThreaded | 如果設置為 true,則即使當前正在使用 parallel ="methods" 運行測試,也保證該測試類上的所有方法都可以在同一線程中運行。 此屬性只能在類級別使用,如果在方法級別使用,則將被忽略 |
timeOut | 超時時間。如果測試運行時間長於該定義時間,測試失敗(單位為毫秒) |
threadPoolSize | 此方法的線程池的大小。 該方法將從 invocationCount 指定的多個線程中調用。 注意:如果未指定 invocationCount,則忽略此屬性 |
TestNG 配置文件
使用示例
- 測試類:
import org.testng.annotations.AfterGroups;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
public class TestConfig {
@BeforeSuite
public void beforeSuite() {
System.out.println("測試套件(當前xml中<suite>標簽)之前運行@BeforeSuite--------------------");
}
@AfterSuite
public void afterSuite() {
System.out.println("測試套件(當前xml中<suite>標簽)之后運行@AfterSuite--------------------\n");
}
@BeforeTest
public void beforeTest() {
System.out.println("測試用例(當前xml中<test>標簽)之前運行@BeforeTest----------");
}
@AfterTest
public void afterTest() {
System.out.println("測試用例(當前xml中<test>標簽)之后運行@AfterTest----------\n");
}
@BeforeMethod
public void beforeMethod() {
System.out.println("當前類每個測試方法(@Test)之前運行@BeforeMethod");
}
@AfterMethod
public void AfterMethod(){
System.out.println("當前類每個測試方法(@Test)之后運行@AfterMethod");
}
@BeforeGroups(value="group1")
public void beforeGroups(){
System.out.println("配置組配group1之前運行@BeforeGroups..................");
}
@AfterGroups(value="group1")
public void afterGroups(){
System.out.println("配置組配group1之后運行@AfterGroups..................");
}
@Test
public void test1(){
System.out.println("runnig com.testng.TestConfig.test1()");
}
@Test(groups="group1")
public void test2(){
System.out.println("runnig com.testng.TestConfig.test2()");
}
@Test(groups="group1")
public void test3(){
System.out.println("runnig com.testng.TestConfig.test3()");
}
}
- 自定義 TestNG 的 xml 配置文件(Maven 項目則將該文件創建在 resource 目錄下):
<?xml version="1.0" encoding="UTF-8"?>
<!-- @BeforeSuite -->
<suite name="tester">
<!-- @BeforeTest -->
<test name="case1">
<classes>
<class name="study.testng.TestConfig" />
<class name="study.testng.TestHelloWorld" />
</classes>
</test>
<!-- @AfterTest -->
<!-- @BeforeTest -->
<test name="case2">
<classes>
<class name="study.testng.TestConfig" />
</classes>
</test>
<!-- @AfterTest -->
</suite>
<!-- @AfterSuite -->
- 執行結果:
測試套件(當前xml中<suite>標簽)之前運行@BeforeSuite--------------------
測試用例(當前xml中<test>標簽)之前運行@BeforeTest----------
當前類每個測試方法(@Test)之前運行@BeforeMethod
runnig com.testng.TestConfig.test1()
當前類每個測試方法(@Test)之后運行@AfterMethod
配置組配group1之前運行@BeforeGroups..................
當前類每個測試方法(@Test)之前運行@BeforeMethod
runnig com.testng.TestConfig.test2()
當前類每個測試方法(@Test)之后運行@AfterMethod
當前類每個測試方法(@Test)之前運行@BeforeMethod
runnig com.testng.TestConfig.test3()
當前類每個測試方法(@Test)之后運行@AfterMethod
Hello World!
配置組配group1之后運行@AfterGroups..................
測試用例(當前xml中<test>標簽)之后運行@AfterTest----------
測試用例(當前xml中<test>標簽)之前運行@BeforeTest----------
當前類每個測試方法(@Test)之前運行@BeforeMethod
runnig com.testng.TestConfig.test1()
當前類每個測試方法(@Test)之后運行@AfterMethod
配置組配group1之前運行@BeforeGroups..................
當前類每個測試方法(@Test)之前運行@BeforeMethod
runnig com.testng.TestConfig.test2()
當前類每個測試方法(@Test)之后運行@AfterMethod
當前類每個測試方法(@Test)之前運行@BeforeMethod
runnig com.testng.TestConfig.test3()
當前類每個測試方法(@Test)之后運行@AfterMethod
配置組配group1之后運行@AfterGroups..................
測試用例(當前xml中<test>標簽)之后運行@AfterTest----------
測試套件(當前xml中<suite>標簽)之后運行@AfterSuite--------------------
從這個結果顯示出注釋的作用位置。其中 @BeforeGroups 和 @AfterGroups 的作用范圍是可以跨類的,但類必須是在同一個測試用例(xml 中的 <test> 標簽)范圍內。
這些標簽的執行順序可以總結為:
@BeforeSuite -> @BeforeTest -> @BeforeClass -> {@BeforeMethod -> @Test -> @AfterMethod} -> @AfterClass -> @AfterTest -> @AfterSuite
(其中 {} 內的與多少個 @Test,就循環執行多少次)
配置文件結構
<?xml version="1.0" encoding="UTF-8"?>
<!--添加dtd約束文件,標簽自動提示-->
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite>
<suite-files>
<suite-file path=""></suite-file>
</suite-files>
<parameter name="" value=""></parameter>
<method-selectors>
<method-selector>
<selector-calss name=""></selector-calss>
</mehod-selector>
</method-selectors>
<test name="">
<parameter name="" value=""><parameter>
<groups>
<define name="">
<include name=""/>
<exclude name=""/>
</define>
<run>
<include name=""/>
<exclude name=""/>
</run>
</groups>
<classes>
<class name="">
<mehods>
<parameter name="" value=""></parameter>
<include name=""></include>
<exclude name=""></exclude>
</methods>
</class>
<class></class>
</classes>
<packages>
<package name="">
<include name=""></include>
<exclude name=""></exclude>
</package>
</packages>
<listeners>
<listener class-name=""/>
</listenters>
</test>
<test></test>
</suite>
配置文件標簽說明
suite 標簽
說明:一個 xml 文件只能有一個 <suite>, 是一個 xml 文件的根級。
<suite> 由 <test> 和 <parameters> 組成。
標簽屬性說明:
屬性 | 說明 | 使用方法 | 參數值 |
---|---|---|---|
name | 名字,將出現在 reports 里 | name="XXX" | suite 名字 |
junit | 是否執行 Junit 模式(識別 setup() 等) | junit="true" | 默認 false |
verbose | 控制台輸出的詳細內容等級:0-10 級(0 無,10 最詳細) | verbose="5" | 0 到 10 |
parallel | 是否在不同的線程並行進行測試,要與 thread-count 配套使用 | parallel="mehods" | (詳見下文)默認 false |
parent-module | 和 Guice 框架有關,只運行一次,創建一個 parent injector 給所有 guice injectors | ||
guice-stage | 和 Guice 框架有關 | guice-stage="DEVELOPMENT" | 值有 DEVELOPMENT、PRODUCTION、TOOL,默認 "DEVELOPMENT" |
configfailurepolicy | 測試失敗后是再次執行還是跳過 | configfailurepolicy="skip" | 值有 skip、continue,默認 "skip" |
thread-count | 與 parallel 配套使用,線程池的大小,決定並行線程數量 | thread-count="10" | 整數,默認 5 |
annotations | 獲取注解,值為 javadoc 時,使用 JavaDoc 的注釋;否則用 JDK5 注釋 | annotations="javadoc" | javadoc |
time-out | 設置parallel時,終止執行單元之前的等待時間(毫秒) | time-out="10000" | 整數,單位毫秒 |
skipfailedinvocationcounts | 是否跳過失敗的調用 | skipfailedinvocationcounts="true" | 默認 false |
data-provider-thread-count | 並發時 data-provider 的線程池數量 | data-provider-thread-count="5" | 整數 |
object-factory | 一個實現 IObjectFactory 接口的類,實例化測試對象 | object-factory="classname" | 類名 |
allow-return-values | 是否允許返回函數值 | all-return-values="true" | 默認 false |
preserve-order | 是否按照排序執行 | preserve-order="true" | 默認 true |
group-by-instances | 按照實例分組 | group-by-instances="true" | 默認 false |
parallel 屬性詳細說明:
- 該參數的值有 false、methods、tests、classes、instances,默認 false。
- parallel 必須和
thread-count
配套使用,否則相當於無效參數,thread-count 決定了並行測試時開啟的線程數量。 parallel="mehods"
:TestNG 將並行執行所有的測試方法在不同的線程里。parallel="tests"
:TestNG 將並行執行在同一個 <test> 下的所有方法在不同線程里。parallel="classes"
:TestNG 將並行執行在相同 <class> 下的方法在不同線程里。parallel="instances"
:TestNG 將並行執行相同實例下的所有方法在不同的線程里。- parent-module 和 guice-stage 和 Guice 框架有關,testNG 6 對 Guice 框架提供了支持。
suite-files 標簽
說明:引入外部的 xml 文件(地址由 path 參數決定,path 必填項),將引入的 xml 與當前的 xml 文件一起使用。
聲明方法:
<suite-files>
<suite-file path="/path/suitefile1"></suite-file>
</suite-files>
test 標簽
說明:一個 <suite> 下可以有多個 <test>,可以通過 <suite> 的 parallel="tests" 來進行並行測試,parallel 必須和 thread-count 配套使用,否則是無效參數。
<test> 由 <parameters>、<groups>、<classes> 三部分組成。
標簽屬性說明:
參數 | 說明 | 使用方法 | 參數值 |
---|---|---|---|
name | test(測試單元)的名字,將出現在報告里 | name="testname" | |
junit | 是否按照 Junit 模式運行 | junit="true" | 默認 false |
verbose | 控制台輸出的詳細內容等級,0-10 級(0 無,10 最詳細),不在報告顯示 | verbose="5" | 0 到 10 |
parallel | 是否在不同的線程並行進行測試,要與 thread-count 配套使用 | parallel="mehods" | 與 suite 的 parallel一致,默認 false |
thread-count | 與 parallel 配套使用,線程池的大小,決定並行線程數量 | thread-count="10" | 整數,默認 5 |
annotations | 獲取注解,值為 javadoc 時,使用 JavaDoc 的注釋;否則用 JDK5 注釋 | annotations="javadoc" | javadoc |
time-out | 設置 parallel 時,終止執行單元之前的等待時間(毫秒) | time-out="10000" | 整數,單位毫秒 |
enabled | 標記是否執行這個 test | enabled="true" | 默認 true |
skipfailedinvocationcounts | 是否跳過失敗的調用 | skipfailedinvocationcounts="true" | 默認 false |
preserve-order | 是否按照排序執行。如果是 true,將按照 xml 文件中的順序去執行 | preserve-order="true" | 默認 true |
allow-return-values | 是否允許返回函數值 | all-return-values="true" | 默認 false |
parameter 標簽
說明:提供測試數據,有 name 和 value 兩個參數。
聲明方法:
<parameter name = "parameter_name" value = "parameter_value "/>
testng.xml 文件中的 <parameter> 可以聲明在 <suite> 或者 <test> 級別,在 <test> 下的 <parameter> 會覆蓋在 <suite> 下聲明的同名變量。
groups 標簽
說明:要運行的組。可以自定義一個組,定義要執行的和要排除的方法。必須和 <classes> 配套使用,從其下的類中找到對應名字的方法。
<groups> 由 <difine> 和 <run>、<dependencies> 三部分組成:
<diffine>
:可以將 group 組成一個新組,包括要執行和不執行的大組。<run>
:要執行的方法。<dependencies>
:指定了某 group 需要依賴的 group(比如下面的例子,group1 需要依賴 group2 和 group3 先執行)。
聲明方法:
<suite name = "TestNG Suite">
<test name = "Grouping">
<groups>
<define name = "All"> <!-- 定義新的分組 -->
<include name = "動物" /> <!-- 測試類中的分組名 -->
<include name = "人" />
</define>
<run>
<include name = "All" /> <!-- 本測試單元執行新定義的分組 -->
</run>
<dependencies>
<group name ="group1" depends-on="goup2 group3"/>
</dependencies>
</groups>
<classes>
<class name = "com.group"/> <!-- 測試程序的全類名 -->
</classes>
</test>
</suite>
classes 標簽
說明:方法選擇器,要執行的方法寫在這里,參數有 name 和 priority。
- <classes> 下必須寫要執行的 <class>,否則不會執行任何內容。如果填寫了 class 沒有寫 methods,會按照填寫的 class 的下的注釋 @Test 去執行所有的方法。
- <classes> 下的 <methods> 如果填寫了 <include>,那么只會執行所填寫的方法,沒有填寫的方法不會去執行。
聲明方法:
<classes>
<class name="要執行的class名">
<methods>
<include name="要執行的方法名"></include>
</methods>
</class>
</classes>
TestNG 參數化
@Parameters
案例:使用 @Parameters 注解從測試配置 xml 文件獲取參數
- 創建測試類:PatamterTest.java
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
/**
* testNG的參數化配置,通過xml文件進行方法的賦值操作
*/
public class PatamterTest {
@Test
@Parameters({"name","age"})
public void showInfo(String name, int age) {
System.out.println("name="+ name + " age=" + age);
}
}
- 創建配置文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="paramterTest">
<test name="transfer">
<classes>
<class name="com.testng.paramter.PatamterTest"/>
<parameter name="name" value="張三"/>
<parameter name="age" value="11"/>
</classes>
</test>
</suite>
-
- 運行結果:
name=張三 age=11
注意:在配置文件中如果定義了多個重名的 parameter,那么后定義的參數值會覆蓋前面的。
@DataProvider
使用步驟:
- 定義一個數據源的方法,通過
@DataProvider
注解來標識。 - 定義一個測試方法,通過
@Test(dataProvider="")
屬性來獲取數據。
示例:
package com.testng;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class DataProviderTest {
/**
* 數據源,是方法提供數據,返回必須是一個二維數組
* @DataProvider(name="data") 通過該注解來標識這個為數據源,name為數據源的名稱。
* @return 返回一個二維數組
*/
@DataProvider(name="data")
public Object[][] providerData() {
Object[][] data = new Object[][] {
{"zhangsan", 12},
{"lisi", 22},
{"wangwu", 32}
};
return data;
}
/**
* 通過dataProvider來獲取數據,執行的次數會根據數據源提供數據的數量
* 例如上面的二維數組長度為3,則該方法會執行三次。
* @param name
* @param age
*/
@Test(dataProvider="data")
public void testDataProvider(String name, int age) {
System.out.println("name=" + name + " age=" + age);
}
}
運行結果:
name=zhangsan age=12
name=lisi age=22
name=wangwu age=32
TestNG 多線程測試
注解方式
invocationCount
:線程調用的次數(默認 1 次)。threadPoolSize
:線程池大小,和 invocationCount 一起使用。如果沒有定義 invocationCount 是沒有效果的。
示例:
import org.testng.annotations.Test;
public class MultiThreadOnAnnotion {
/**
* 表示開啟3個線程,共執行該方法10次
*/
@Test(invocationCount=10, threadPoolSize=3)
public void test(){
System.out.printf("Thread Id : %s%n", Thread.currentThread().getId());
}
}
執行結果:
Thread Id : 11
Thread Id : 12
Thread Id : 13
Thread Id : 13
Thread Id : 13
Thread Id : 13
Thread Id : 11
Thread Id : 12
Thread Id : 13
Thread Id : 12
xml 配置方式
- 創建測試類:
import org.testng.annotations.Test;
/**
* 使用配置文件來實現testng的多線程
*/
public class MultiThreadOnXml {
@Test
public void test1() {
System.out.printf("Thread id: %s%n", Thread.currentThread().getId());
}
@Test
public void test2() {
System.out.printf("Thread id: %s%n", Thread.currentThread().getId());
}
@Test
public void test3() {
System.out.printf("Thread id: %s%n", Thread.currentThread().getId());
}
@Test
public void test4() {
System.out.printf("Thread id: %s%n", Thread.currentThread().getId());
}
}
- 創建配置文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="thread" parallel="methods" thread-count="3">
<!--
parallel:
tests級別:不同的 test tag 下的用例可以在不同的線程下執行
相同的 test tag 下的用例只能在同一個線程中去執行
classs級別:不同的 class tag 下的用例可以在不同的線程中執行
相同的 class tag 下的用例在同一個線程中執行
methods級別:所有用例都可以在不同的線程下去執行
thread-count:代表了最大並發線程數
xml文件配置這種方式不能指定線程池,只有方法上才可以指定線程池
-->
<test name="test1">
<classes>
<class name="com.testng.MultiThreadOnXml"/>
</classes>
</test>
</suite>
- 執行結果:
Thread id: 12
Thread id: 13
Thread id: 11
Thread id: 12