1. 程式人生 > >TestNG 單元測試框架

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> 表示定義了的一個測試套件。
  1. name 定義測試套件的名稱。
  2. verbose 定義命令列資訊列印等級,不會影響測試報告輸出內容;可選值(1|2|3|4|5) 
  • <test>...</test> 表示定義了一個測試。
  1. name 定義測試的名稱。
  • <classes>...</classes> 表示定義一組測試類。
  • <class .../> 表示定義一個測試類。
  1. 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.../> 定義一個測試包。
  1. 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.../> 指定包含的測試用例(方法)。
  1. 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的設定,指定執行的測試用例。
根據上面的配置,執行測試: testCase1 和 testCase2 兩條用例將被執行。

不要忘了,我們給 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.../> 定義測試資料
  1. name 定義資料的名字,在測試用例中通過該名字來獲取對應的vlaue。
  2. 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 用來預設用例執行會出現的異常。例如 20 將會丟擲 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 測試用例一樣可以生成報告了。