TestNG 單元測試框架
(一)TestNG介紹與安裝
1、介紹
TestNG 官網地址:http://testng.org/doc/
TestNG是一個測試框架的靈感來自JUnit和NUnit,但引入一些新的功能,使它更強大和更容易使用,如:
- 註釋。
- 在任意大執行緒池中執行測試,並提供各種策略(所有方法都在自己的執行緒中,每個測試類有一個執行緒,等等)。
- 測試你的程式碼多執行緒是安全的。
- 靈活的測試配置。
- 資料驅動的測試支援(@dataProvider)。
- 引數支援。
- 強大的執行模型(不再有TestSuite)。
- 通過各種工具和外掛支援(Eclipse, IDEA, Maven 等..)。
- 通過進一步的靈活性Beanshell。
- 執行時和日誌的預設JDK功能(無依賴性)。
- 應用伺服器測試的相關方法。
- TestNG 表示下一代(Next Generation的首字母)。它的設計覆蓋所有類別的測試:單元、功能、端到端、整合等。
2、安裝
本教程基於 IntelliJ IDEA 和 Maven ,所以,這裡只介紹 Maven 的安裝方式。
<!-- https://mvnrepository.com/artifact/org.testng/testng --> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.13</version> <scope>test</scope> </dependency>
(二)第一個測試用例
1、第一個測試用例
通過 IntelliJ IDEA 建立 FirstTest 測試類。編寫如下程式碼:
import org.testng.annotations.Test;
import static org.testng.AssertJUnit.assertEquals;
public class FirstTest {
@Test
public void testCase(){
assertEquals(2+2, 4);
}
}
通過 @Test 註解一個方法為測試用例。
通過 assertEquals() 方法來斷言兩個數是否相等。
執行測試:
===============================================
Default Suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
我們先感官上對TestNG使用有一個初步認識。
(三)TestNG 之 FixTrue
1、什麼是Fixture
Test Fixture 是指一個測試執行所需的固定環境,準確的定義:
The test fixture is everything we need to have in place to exercise the SUT
在進行測試時,我們通常需要把環境設定成已知狀態(如建立物件、獲取資源等)來建立測試,每次測試開始時都處於一個固定的初始狀態;測試結果後需要將測試狀態還原,所以,測試執行所需要的固定環境稱為 Test Fixture。
2、TestNG 提供的Fixture 方法
表:
註解 | 說明 |
---|---|
@BeforeSuite | 註解的方法在測試套件(中的所有用例)開始前執行一次 |
@AfterSuite | 註解的方法在測試套件(中的所有用例)結束後執行一次。 |
@BeforeClass | 註解的方法在當前測試類(中所有用例)開始前執行一次。 |
@AfterClass | 註解的方法在當前測試類(中所有用例)結束後執行一次。 |
@BeforeTest | 對於套件測試,在執行屬於標籤內的類的所有測試方法之前執行。 |
@AfterTest | 對於套件測試,在執行屬於標籤內的類的所有測試方法之後執行。 |
@BeforeGroups | 在呼叫屬於該組的所有測試方法之前執行。 |
@AfterGroups | 在呼叫屬於該組的所有測試方法之後執行。 |
@BeforeMethod | 註解的方法將在每個測試方法之前執行。 |
@AfterMethod | 註釋的方法將在每個測試方法之後執行。 |
3、例項
接下來通過例子演示上面部分註解的用法。
import org.testng.annotations.*;
public class FixtureTest {
//在當前測試類開始時執行。
@BeforeClass
public static void beforeClass(){
System.out.println("-------------------beforeClass");
}
//在當前測試類結束時執行。
@AfterClass
public static void afterClass(){
System.out.println("-------------------afterClass");
}
//每個測試方法執行之前執行
@BeforeMethod
public void before(){
System.out.println("=====beforeMethod");
}
//每個測試方法執行之後執行
@AfterMethod
public void after(){
System.out.println("=====afterMethod");
}
@Test
public void testCase1(){
System.out.println("test case 1");
}
@Test
public void testCase2(){
System.out.println("test case 2");
}
}
執行上面的測試,執行結果如下。
-------------------beforeClass
=====beforeMethod
test case 1
=====afterMethod
=====beforeMethod
test case 2
=====afterMethod
-------------------afterClass
===============================================
Default Suite
Total tests run: 2, Failures: 0, Skips: 0
===============================================
(四)testng.xml檔案解析
TestNG 與 Junit 比較大的一個差異就是前者通過 testng.xml 檔案來配置測試用例的執行。 testng.xml檔案可以很好的控制要執行的測試用例的粒度,及各種執行策略。
目前testng.xml DTD(Document Type Definition; DTD是一種XML的約束方式。) 配置說明可以在:這裡
1、testng.xml 檔案解析
<suite name="Suite1" verbose="1" >
<test name="Nopackage" >
<classes>
<class name="NoPackageTest" />
</classes>
</test>
<test name="Regression1">
<classes>
<class name="test.sample.ParameterSample"/>
<class name="test.sample.ParameterTest"/>
</classes>
</test>
</suite>
-
- <suite>...</suite> 表示定義了的一個測試套件。
- name 定義測試套件的名稱。
- verbose 定義命令列資訊列印等級,不會影響測試報告輸出內容;可選值(1|2|3|4|5)
- <test>...</test> 表示定義了一個測試。
- name 定義測試的名稱。
- <classes>...</classes> 表示定義一組測試類。
- <class .../> 表示定義一個測試類。
- name 指定要執行的測試類
2、例項
測試專案目錄結果如下:
testng.xml 配置檔案如下:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="測試套件" verbose="1" >
<test name="簡單測試">
<classes>
<class name="test.sample.FirstTest"/>
<class name="test.sample.SecondTest"/>
</classes>
</test>
</suite>
- <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > 必須要新增,表示遵循的規範檔案。
在 testng.xml 檔案上右鍵點選執行測試。
執行結果如下:
(五)測試級別設定
在我們建立測試用例時,大概分三個層級。
- 測試包(目錄)
- 測試類(檔案)
- 測試用例(@Test 註解的方法)
接下來介紹,如何控制這三個級別用例的執行。當然,核心還是通過 testng.xml 檔案配置。
1、指定執行測試包
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="測試套件" verbose="1" >
<test name="簡單測試">
<packages>
<package name="test.sample" />
<package name="test.sample2" />
</packages>
</test>
</suite>
- <packages>...</packages> 定義一組測試包。
- <package.../> 定義一個測試包。
- name 指定測試包(目錄)的名稱。
2、指定執行測試類
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="測試套件" verbose="1" >
<test name="簡單測試">
<classes>
<class name="test.sample.FirstTest"/>
<class name="test.sample.SecondTest"/>
</classes>
</test>
</suite>
指定測試類的執行,上一節已經介紹。
3、指定執行測試用例
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="測試套件" verbose="1" >
<test name="簡單測試">
<classes>
<class name="test.sample.FirstTest">
<methods>
<include name="testCase" />
</methods>
</class>
</classes>
</test>
</suite>
- <methods>...</methods> 定義一組測試方法。
- <include.../> 指定包含的測試用例(方法)。
- name 指定測試用例(方法)的名稱。
注意: 測試方法<methods>必須包含在<class>標籤中。
(六)TestNG 用例分組
有時候我們的測試用例並不想以測試包、類和用例為單位去執行。測試用例可以有多個緯度去標識。
例如,可以根據用例的重要程度劃分:
重要程度:低——>中——>高
或者,根據用例的型別劃分:
型別:正常——>異常
TestNG 允許我們給測試用例貼標籤。我們可以根據這些標籤有選擇地的跳過或執行這些用例。
1、例項
import org.testng.annotations.Test;
import static org.testng.AssertJUnit.assertEquals;
@Test(groups = {"功能測試"})
public class TagTest {
@Test(groups={"高", "正常"})
public void testCase1(){
assertEquals(2+2, 4);
}
@Test(groups = {"高", "正常"})
public void testCase2(){
assertEquals(5-3, 2);
}
@Test(groups = {"中", "正常"})
public void testCase3(){
assertEquals(2/1, 2);
}
@Test(groups = {"低", "異常"})
public void testCase4(){
assertEquals(2/0, 1);
}
}
接下來配置 testng.xml ,根據標籤篩選要執行的測試用例。
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="測試套件" verbose="1" >
<test name="簡單測試">
<groups>
<run>
<exclude name="異常" /> <!-- 排除不執行的測試用例 -->
<include name="高" /> <!-- 指定執行的測試用例 -->
</run>
</groups>
<classes>
<class name="test.sample.TagTest"/>
</classes>
</test>
</suite>
- <groups>...</groups> 測試組標籤。
- <run>...</run> 執行測試。
- <exclude> 根據groups的設定,排除不執行的用例。
- <include> 根據groups的設定,指定執行的測試用例。
不要忘了,我們給 TagTest 測類同樣也劃分了組(groups = {"功能測試"}),現在修改 testng.xml 配置。
……
<groups>
<run>
<exclude name="異常" /> <!-- 排除不執行的測試用例 -->
<include name="功能測試" /> <!-- 指定執行的測試用例 -->
</run>
</groups>
……
再次執行測試:testCase1、testCase2 和 testCase3 三條用例將被執行。
(七)TestNG 用例執行順序
有時候,我們希望用例按照我們要求的順序來執行。TestNG 同樣可以滿足這一點要求。
1、例項
import org.testng.annotations.Test;
import static org.testng.AssertJUnit.assertEquals;
public class CaseRunTest {
@Test
public void testCase1(){
assertEquals(2+2, 4);
}
@Test
public void testCase2(){
assertEquals(2+2, 4);
}
@Test
public void testCase3(){
assertEquals(2+2, 4);
}
}
通過 testng.xml 檔案修改配置。
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="測試套件">
<test name="簡單測試" preserve-order="false">
<classes>
<class name="test.sample.CaseRunTest">
<methods>
<include name="testCase3" />
<include name="testCase1" />
<include name="testCase2" />
</methods>
</class>
</classes>
</test>
</suite>
- preserve-order 引數用於控制測試用例的執行順序。如果為:true,測試用例的順序為:testCase > testCase1 > testCase2。如果為:false ,那麼預設會按照用例的名稱的有字母/數字的順序執行:testCase1 > testCase2 > testCase3。
不設定的情況下預設為 true 。
(八)TestNG 用例依賴
當某一條用例執行失敗時,其它用例必然也會失敗,所以,我們就沒有必要再執行其它用例了,這個時候我們就可以設定用例之間的依賴。
1、測試方法依賴
import org.testng.annotations.Test;
import static org.testng.AssertJUnit.assertEquals;
public class DependentMethodsTest {
@Test
public void testAdd1(){
assertEquals(3+1, 5);
}
@Test(dependsOnMethods = {"testAdd1"})
public void testAdd2(){
assertEquals(3+2, 5);
}
}
- dependsOnMethods 來設定用例的依賴,當 testAdd1() 執行失敗時,則 testAdd2() 不再被執行。
2、測試組依賴
import org.testng.annotations.Test;
import static org.testng.AssertJUnit.assertEquals;
public class DependentGroupsTest {
@Test(groups={"funtest"})
public void testAdd1(){
assertEquals(3+1, 5);
}
@Test(groups={"funtest"})
public void testAdd2(){
assertEquals(3+2, 5);
}
@Test(dependsOnGroups = {"funtest"})
public void testAdd3(){
assertEquals(3+2, 5);
}
}
- dependsOnGroups 來設定組的依賴,testAdd1()和 testAdd2() 同屬于于 funtest組,testAdd3() 依賴於funtest組,該組有中有一條用例執行失敗,則testAdd3() 不再執行。
(九)TestNG 用例引數化
引數化也測試用例中常用的技巧之一,它可以增加用例的可配置性和減少相同用例的編寫。
1、通過 @Parameters 實現引數化
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
import static org.testng.AssertJUnit.assertEquals;
public class DataProviderTest {
@Test
@Parameters({"add1","add2","result"})
public void testAdd1(int add1, int add2, int result){
assertEquals(add1+ add2, result);
}
}
- @Parameters 獲取引數化資料,作為 testAdd1() 測試方法的引數。
具體的測試資料在 testng.xml 檔案中設定。
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="測試套件">
<test name="簡單測試">
<parameter name="add1" value="3"/>
<parameter name="add2" value="2"/>
<parameter name="result" value="5"/>
<classes>
<class name="test.sample.DataProviderTest" />
</classes>
</test>
</suite>
- <parameter.../> 定義測試資料
- name 定義資料的名字,在測試用例中通過該名字來獲取對應的vlaue。
- value 定義測試資料,通過對應的name來獲取該值。
2、通過 @DataProvider 實現引數化
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.AssertJUnit.assertEquals;
public class DataProviderTest {
// 定義物件陣列
@DataProvider(name = "add")
public Object[][] Users() {
return new Object[][] {
{ 3, 2, 5 },
{ 2, 2, 4 },
{ 3, 3, 7 },
};
}
@Test(dataProvider="add")
public void testAdd2(int add1, int add2, int result){
assertEquals(add1+add2, result);
}
}
- @DataProvider 定義物件陣列,陣列的名稱為:add 。
在 testAdd2() 中通過 dataProvider="add" 呼叫定義的物件陣列,並通過引數獲取相應的測試資料。
執行結果如下:
(十) TestNG 多執行緒執行用例
TestNG 是我接觸過的唯一自身支援多程技術的單元測試框架。雖然程式碼級別的單元測試執行得很快,多執行緒的意義並不大。但如果是UI自動化測試的話執行速度就會非常慢,這個時候多執行緒技術就會變得很重要。
1、多執行緒配置
這裡只介紹 testng.xml 檔案,其中的使用到的測試用例,請參考前面的章節建立。
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="測試套件" parallel="classes" thread-count="2" >
<test name="簡單測試">
<classes>
<class name="test.sample.FirstTest" />
<class name="test.sample.SecondTest" />
</classes>
</test>
</suite>
parallel 設定多執行緒的級別劃分。
parallel=“methods”: TestNG將在不同的執行緒中執行所有的測試方法。依賴方法也將在單獨的執行緒中執行,但它們將尊重你指定的順序。
parallel=“tests”: TestNG 將在同一個執行緒中執行相同的標記的所有方法,但是每個標記將在一個單獨的執行緒中。這允許你將所有非執行緒安全的類分組在同一個中,並保證它們將在同一個執行緒中執行,同時利用盡可能多的執行緒來執行測試。
parallel=“classes”: TestNG將在同一個執行緒中運行同一個類中的所有方法,但是每個類都將在一個單獨的執行緒中執行。
parallel=“instances”: TestNG將在同一個執行緒中執行相同例項中的所有方法,但是在兩個不同例項上的兩個方法將在不同的執行緒中執行。
thread-count 用於指定執行緒的個數。
(十一)TestNG 其他使用技巧
除了前面介紹的功能外,TestNG 還有一些使用技巧,相對比較簡單,這裡通過一個例子來演示。
1、其它使用技巧
import org.testng.annotations.Test;
import static org.testng.AssertJUnit.assertEquals;
public class OtherTest {
// 該條用例跳過執行
@Test(enabled = false)
public void testCase1(){
assertEquals(2+2, 4);
}
// 設定用例超時時間
@Test(timeOut = 3000)
public void testCase2() throws InterruptedException {
Thread.sleep(3001);
}
// 預設用例丟擲的異常型別
@Test(expectedExceptions = RuntimeException.class)
public void testCase3(){
assertEquals(2/0,1);
}
}
enabled 設定用例是否跳過執行,預設為:true ,表示不跳過。false 表示跳過執行。
timeOut 設定用例執行的超時間,3000 單位為毫秒,當用例執行時間超過 3000 毫秒則判定為失敗。不管用例本身是否執行失敗。
expectedExceptions 用來預設用例執行會出現的異常。例如 2⁄0 將會丟擲 RuntimeException 型別的異常,如果出現異常則表示用例執行成功。
(十二)TestNG 生成測試報告
TestNG 預設自帶的有HTML格式的測試報告。這也充分說明拿它來做 UI 自動化測試的優勢。
1、通過 Maven 生成報告
切換到 TestngTest 專案的跟目錄下,通過 mvn test 命令執行測試。
TestngTest> mvn test
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building TestngTest 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ TestngTest
--- [WARNING] Using platform encoding (GBK actually) to copy filtered resources,
i.e. build is platform dependent!
[INFO] Copying 0 resource
...
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running TestSuite
Configuring TestNG with: [email protected]3b2
Tests run: 19, Failures: 5, Errors: 0, Skipped: 2, Time elapsed: 3.862 sec <<< FAILURE!
在該系列教程開始前,我已經說明了整個專案基於 Maven 建立。
現在開啟 ..\TestngTest\target\surefire-reports\index.html 將會看到整個專案的執行結果。
2、通過 IntelliJ IDEA 生成測試報告
在 IntelliJ IDEA 中預設執行測試用例是不會生成HTML報告的,需要進行簡單的配置。
選單欄: “Run” –>“Edit Configuraction…” 。
如上圖,選擇執行測試用例的 testng.xml 檔案–>“Configuration”–>“Listeners”–> 勾選“Use default reporters” 選項, 最後點選“OK” 按鈕, 完成設定。
好了! 現在用 IntelliJ IDEA 執行 TestNG 測試用例一樣可以生成報告了。