TestNG


. 介紹
    TestNG是一個設計用來簡化廣泛的測試需求的測試框架,從單元測試(隔離測試一個類)到集成測試(測試由有多個類多個包甚至多個外部框架組成的整個系統,例如運用服務器)。

    編寫一個測試的過程有三個典型步驟:

    * 編寫測試的 業務邏輯並在代碼中插入TestNG annotation
    * 將測試信息添加到testng.xml文件或者build.xml中
    * 運行TestNG

在歡迎頁面上可以找到快速入門示例。

下面是這篇文檔使用的概念:

    * suite由xml文件描述。它包含一個或多個測試並被定義爲<suite>標籤
    * test由<test>描述幷包含一個或者多個TestNG類
    * TestNG類是包含至少一個TestNG annotation的java類,由<class>標籤描述幷包含一個或多個測試方法
    * 測試方法是源文件中帶有@Testd註釋的java方法

    TestNG測試可以被@BeforeXXX 和 @AfterXXX annotations配置,容許在特定點的前後執行一些java邏輯,這些點上面已經列出。

這份手冊的剩餘部分將講述以下內容:

    * 所有的annotation列表並帶有簡短說明,爲TestNG的多種功能性提供參考, 你可能需要參考爲每個annotation提供的代碼片段來學習細節。

     * testng.xml文件描述,它的語法和如果指定它。
    * 多個特性的詳細列表和怎樣結合annotation和testng.xml來使用它們

*******************************************************************************

注:上面的內容很簡短,但是請注意其中的一些細節。

1. TestNG是一個設計用來簡化廣泛的測試需求的測試框架,從單元測試到集成測試
    這個是TestNG設計的出發點,不僅僅是單元測試,而且可以用於集成測試。設計目標的不同,對比junit的只適合用於單元測試,TestNG無疑走的更遠。
    可以用於集成測試,這個特性是我選擇TestNG的最重要的原因。

2. 測試的過程的三個典型步驟,注意和junit(4.0)相比,多了一個將測試信息添加到testng.xml文件或者build.xml
    測試信息尤其是測試數據不再寫死在測試代碼中,好處就是修改測試數據時不需要修改代碼/編譯了,從而有助於將測試人員引入單元測試/集成測試。

3. 基本概念,相比junit的TestCase/TestSuite,TestNG有suite/test/test method三個級別,即將test/test method明確區分開了。
    junit中的TestCase將test/test method混合,比較容易讓人概念不清晰,尤其是新手。

2 - Annotation

這裏是TestNG中用到的annotation的快速預覽,還有它們的屬性。


@BeforeSuite:        被註釋的方法將在所有測試運行前運行
@AfterSuite:        被註釋的方法將在所有測試運行後運行
@BeforeTest:        被註釋的方法將在測試運行前運行
@AfterTest:        被註釋的方法將在測試運行後運行
@BeforeGroups:        被配置的方法將在列表中的gourp前運行。這個方法保證在第一個屬於這些組的測試方法調用前立即執行。
@AfterGroups:        被配置的方法將在列表中的gourp後運行。這個方法保證在最後一個屬於這些組的測試方法調用後立即執行。
@BeforeClass:        被註釋的方法將在當前類的第一個測試方法調用前運行。
@AfterClass:        被註釋的方法將在當前類的所有測試方法調用後運行。
@BeforeMethod:        被註釋的方法將在每一個測試方法調用前運行。
@AfterMethod:        被註釋的方法將在每一個測試方法調用後運行。
屬性:
    alwaysRun    對於每個bufore方法(beforeSuite, beforeTest, beforeTestClass 和 beforeTestMethod, 但是不包括 beforeGroups): 
                如果設置爲true,被配置的方法將總是運行而不管它屬於哪個組。
                對於after方法(afterSuite, afterClass, ...): 如果設置爲true,被配置的方法甚至在一個或多個先調用的方法失敗或被忽略時也將運行。
    dependsOnGroups        這個方法依賴的組列表
    dependsOnMethods    這個方法依賴的方法列表
    enabled            這個類的方法是否激活
    groups            這個類或方法所屬的分組列表
    inheritGroups        如果設置爲true,這個方法被屬於在類級別被@Test annotation指定的組
 
@DataProvider    標記一個方法用於爲測試方法提供數據。
                被註釋的方法必須返回Object[][], 其中每個Object[]可以指派爲這個測試方法的參數列表。
                從這個DataProvider接收數據@Test方法需要使用一個和當前註釋相同名稱的dataProvider名稱
    name         這個DataProvider的名稱
 
@Factory    標記方法作爲一個返回對象的工廠,這些對象將被TestNG用於作爲測試類。這個方法必須返回Object[]
 
@Parameters    描述如何傳遞參數給@Test方法
    value    用於填充這個方法的參數的變量列表
 
@Test        標記一個類或方法作爲測試的一部分
    alwaysRun     如果設置爲true,這個測試方法將總是運行,甚至當它依賴的方法失敗時。
    dataProvider     這個測試方法的data provider的名稱
    dataProviderClass     用於查找data provider的類。
                    如果不指定,將在當前測試方法所在的類或者它的基類上查找data provider。
                    如果這個屬性被指定, 則data provider方法需要是指定類的static方法。
    dependsOnGroups     當前方法依賴的組列表
    dependsOnMethods     當前方法依賴的方法列表
    description     當前方法的描述
    enabled     當前類的方法/方法是否被激活
    expectedExceptions     測試方法期望拋出的異常列表。如果沒有異常或者拋出的不是列表中的任何一個,當前方法都將標記爲失敗.
    groups     當前類/方法所屬的組列表
    invocationCount     當前方法被調用的次數
    successPercentage     當前方法期望的成功率
    sequential     如果設置爲true,當前測試類上的所有方法保證按照順序運行。甚至測試們在parallel="true"的情況下.
            這個屬性只能用於類級別,如果用於方法級別將被忽略。
    timeOut     當前方法容許花費的最大時間,單位毫秒。
    threadPoolSize     當前方法的線程池大小。方法將被多線程調用,次數由invocationCount參數指定
            注意:如果invocationCount沒有指定則這個屬性將被忽略


注:
    上面是TestNG中用到的annotation列表,從中我們可以看到TestNG提供的一些特性

1. before方法和after方法    帶來了足夠豐富的測試生命週期控制
2. dependsOnGroups/dependsOnMethods 提供了依賴檢查機制,並可以嚴格控制執行順序
3. DataProvider 使得對同一個方法的測試覆蓋變的非常輕鬆,非常適合進行邊界測試,只要給出多種測試數據就可以針對一個測試方法進行覆蓋
4. expectedExceptions 使得異常測試變的非常輕鬆
5. invocationCount/threadPoolSize 終於可以簡單的直接進行多線程測試了,這個絕對是junit的超級弱項,回想junit中那個萬惡的System.exist(0)...
6. timeOut 終於不用死等然後手工強行關閉測試,TestNG想的太周到了

TestNG官方文檔中文版(3)-testng.xml 
    TestNG的官方文檔的中文翻譯版第3章,原文請見 http://testng.org/doc/documentation-main.html

    3 - testng.xml

    調用TestNG由幾種不同方法:

    * 使用testng.xml文件
    * 使用ant
    * 從命令行

    這節描述testng.xml的格式(文檔的後面會講到ant和命令行)。

    當前testng.xml的DTD文件可以從官方找到:http://testng.org/testng-1.0.dtd。(爲了方便使用,你可能更喜歡瀏覽HTML版本)。
    下面是testng.xml文件的一個例子:

  1. <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >  
  2.    
  3. <suite name="Suite1"    verbose="1" >  
  4.   <test name="Nopackage" >  
  5.     <classes>  
  6.        <class name="NoPackageTest"  />  
  7.     </classes>  
  8.   </test>  
  9.   <test name="Regression1"   >  
  10.     <classes>  
  11.       <class name="test.sample.ParameterSample"  />  
  12.       <class name="test.sample.ParameterTest" />  
  13.     </classes>  
  14.   </test>  
  15. </suite>  
 

    你可以指定包名替代類名:

  1. <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >  
  2. <suite name="Suite1" verbose="1" >  
  3.   <test name="Regression1"   >  
  4.     <packages>  
  5.       <package name="test.sample" />  
  6.    </packages>  
  7.  </test>  
  8. </suite>  
 

    在這個例子中,TestNG將在包test.sample中查找所有的類,並只保留帶有TestNG annotation的類。

    你同樣可以指定包含或不包含的組和方法:

  1. <test name="Regression1">  
  2.   <groups>  
  3.     <run>  
  4.       <exclude name="brokenTests"  />  
  5.       <include name="checkinTests"  />  
  6.     </run>  
  7.   </groups>  
  8.    
  9.   <classes>  
  10.     <class name="test.IndividualMethodsTest">  
  11.       <methods>  
  12.         <include name="testMethod" />  
  13.       </methods>  
  14.     </class>  
  15.   </classes>  
  16. </test>  
 

    你同樣可以在testng.xml中定義新的組,指定屬性的額外詳細情況,比如是否並行運行測試,使用多少線程,是否運行junit測試,等等...
    請查看DTD文件瞭解完整的特性列表。

4 - 運行TestNG

TestNG可以以不同的方式調用:

    * Command line
    * ant
    * Eclipse
    * IntelliJ's IDEA

1) 命令行

假設你已經將TestNG加入到class path,調用TestNG最簡單的方法事下面的:

java org.testng.TestNG testng1.xml [testng2.xml testng3.xml ...]

必須指定最少一個描述你試圖測試的TestNG suite的xml文件。另外,下面的命令行參數可以使用:

命令行參數列表

選項        參數                文檔說明
-d        一個目錄            生成報告的目錄( test-output)
-sourcedir    分號隔開的目錄列表        帶有javadoc註釋的測試源文件目錄. 這個選項只在使用javadoc類型的annotation時纔有效. 
                        (例如 "src/test" or "src/test/org/testng/eclipse-plugin;src/test/org/testng/testng").
-testclass    可以在classpath路徑中找到的逗號分隔的類列表。逗號分隔的類文件列表(例如 "org.foo.Test1,org.foo.test2").
-groups        逗號分隔的組列表        要運行的組列表(例如 "windows,linux,regression").
-excludegroups    逗號分隔的組列表        不想包含在這次運行中的組列表
-testrunfactory    可以在classpath中找到的java類    指定測試的runner.這個類需要實現接口org.testng.ITestRunnerFactory .
-listener    可以在classpath路徑中找到的逗號分隔的類列表。    指定測試的listener. 這個類需要實現接口org.testng.ITestListener
-parallel    methods|tests            如果指定, 設置運行測試時如何使用併發線程的默認機制.如果不設置,默認機制是完全不使用併發線程。這個設置可以被suite定義覆蓋.
-threadcount    併發測試運行時默認使用的線程數    用於設置併發測試時默認的線程數. 只在併發模式被選擇時才生效 (例如, 打開 -parallel 選項). 這個設置可以被suite定義覆蓋.
-suitename    測試套件使用的默認名稱.        指定在命令行上定義的測試套件的名稱。如果suite.xml文件或源代碼指定了另外一個不同的套件名稱,這個選項將被忽略。可以創建帶空格的套件名稱,如果在名稱前後加雙引號如"like this".
-testname    測試使用的默認名稱.        指定在命令行上定義的測試的名稱。如果suite.xml文件或源代碼指定了另外一個不同的測試名稱,這個選項將被忽略。可以創建帶空格的測試名稱,如果在名稱前後加雙引號如"like this".
-reporter    擴展配置用於自定義報告listenner.    類似 -listener 選項, 除了容許reporter示例上由javabean形式的配置.
    例如: -reporter com.test.MyReporter:methodFilter=*insert*,enableFiltering=true

可以通過不帶任何參數直接調用TestNFG來獲得這個文檔。

可以將命令行開關寫到txt文件中,例如c:/command.txt, 然後告訴TestNG使用這個文件類找到參數:

  C:> more c:/command.txt
  -d test-output testng.xml
  C:> java org.testng.TestNG @c:/command.txt

另外,可以通過jvm的命令行來傳遞參數給TestNG,例如

java -Dtestng.test.classpath="c:/build;c:/java/classes;" org.testng.TestNG testng.xml

TestNG能夠理解的參數
屬性             類型                     文檔
testng.test.classpath     分號分隔的包含測試類的一系列目錄     如果這個屬性被設置,TestNG將使用它替代從class path來查找測試類. 如果你正在使用在xml文件裏面的包標籤並且在classpath路徑中由很多類而大部分都不是測試類的時候比較方便

舉例:

java org.testng.TestNG -groups windows,linux -testclass org.test.MyTest

注意 ant 任務和testng.xml容許用更多的參數來啓動TestNG(包含的方法,指定的參數,等等),因此可以認爲命令行適用於學習TestNG並且想快速入門。


2) Ant

可以這樣定義TestNG的ant任務:

<taskdef resource="testngtasks"
         classpath="testng.jar"/>

這個任務運行TestNG測試,並且通常是在單獨的jvm中。接受下面的屬性:

屬性名            描述                是否必須
annotations         字符串"JDK"或者"Javadoc". 定義測試適用的註釋類型.如果使用"Javadoc", 則需要同時指定"sourcedir".     不是必須. 如果適用jkd5則默認爲"JDK",如果適用jdk1.4則默認爲"Javadoc"
classfilesetref     要運行的測試類的FileSet結構的引用.      
classpath         要運行的測試的PATH-like 結構.      
classpathref         要運行的測試的PATH-like 結構的引用.      
dumpCommand         打印TestNG啓動命令.     不是必須,默認false
enableAssert         開啓JDK 1.4的斷言.     不是必須,默認true
failureProperty     失敗發生時要設置的屬性的名稱. 只有haltonfailure沒有設置時纔有效.     不是必須.
haltonfailure         如果測試運行期間發生失敗,停止構造過程.     不是必須,默認false
haltonskipped         如果發生至少一次測試跳過,停止構造過程.        不是必須,默認false
groups             要運行的組列表,空格或逗號分隔    
excludedgroups         排除在外的組列表,空格或逗號分隔
jvm             使用的jvm,將被Runtime.exec()運行     java
listeners         逗號或空格分隔的全路徑類列表,需要實現org.testng.ITestListener或org.testng.IReporter     不是必須
outputdir         報告輸出目錄             不是必須,默認輸出到test-output.
skippedProperty     當發生測試被跳過時設置的property的名稱.只有當haltonskipped沒有設置時才使用     不是必須
sourcedir         用於jdk1.4測試的PATH-like結構(使用JavaDoc形式的annotations)      
sourcedirref         用於jdk1.4測試的PATH-like結構的引用(使用JavaDoc形式的annotations)           
suiteRunnerClass     TestNG啓動器的全路徑名稱    不是必須.  默認使用org.testng.TestNG
parallel         運行測試時使用的並行模式 - methods或者tests     不是必須 - 如果沒有指定,並行模式不被選擇
threadCount         運行時使用的線程數量。如果並行模式被同時指定否則忽略。     默認1
testJar         包含測試和套件定義的jar包路徑
timeOut         所有測試必須運行完成的最大超時時間,單位毫秒 
useDefaultListeners     是否使用默認監聽器和報告器.     默認true.
workingDir         運行TestNG前ant任務應該轉移到的目錄。
xmlfilesetref        用於要測試的套件定義的FileSet結構的引用      
suitename         設置測試套件的默認名稱如果在suite的xml文件或者源代碼中都沒有被定義。    不是必須,默認設置爲"Ant suite"
testname        設置測試的默認名稱如果在suite的xml文件或者源代碼中都沒有被定義。    不是必須,默認設置爲"Ant test"


屬性classpath, classpathref或者內嵌的<classpath>必須設置一個,用於提供測試的classpath

屬性xmlfilesetref, classfilesetref 或者內嵌的 <xmlfileset>, 分別的<classfileset>必須使用用來提供測試

注意:如果使用jdk1.4,屬性attributes sourcedir, sourcedirref 或者內嵌的 <sourcedir> 必須提供.

注意:使用<classfileset> 並不自動按添加測試類到classpath: 需要報告這些在classpath中的任務要工作的類

內嵌元素
classpath
 <testng> 任務支持一個內嵌的<classpath> 元素來提供PATH-like的結構.

bootclasspath
bootstrap類文件的位置可以用這個PATH形式的結構指定-如果fork沒有設置則被忽略

xmlfileset
套餐定義(testng.xml)可以通過一個FiltSet結構傳遞給任務

classfileset
TestNG可以直接在類上運行,同樣支持FiltSet結構

sourcedir
PATH形式的結構,用於jdk1.4的測試,使用javadoc annotation

jvmarg
通過內嵌的<jvmarg>元素將額外的參數傳遞給新的虛擬機,例如:

<testng>
   <jvmarg value="-Djava.compiler=NONE" />
   <!-- ... -->
</testng>

sysproperty
使用內嵌的<sysproperty>元素來指定類需要的系統屬性。在測試的執行期間虛擬機可以獲取這些屬性。 這個元素的屬性和環境變量相同。

  1. <testng>  
  2.    <sysproperty key="basedir" value="${basedir}"/>  
  3.    <!-- ... -->  
  4. </testng>  

將運行測試並且使得測試可以訪問basedir屬性

reporter

內部的<reporter>元素是一個可選的方式,用於注入自定義的報告監聽器,容許用戶爲調整運行時的報告期行爲而
這個元素強制要求設置classname屬性,指示自定義監聽器的類。爲了設置報告期屬性,<reporter>元素可以包含多個內嵌的<property>元素來提供name和value屬性,如下所示:

 

請注意這裏僅僅支持有限的屬性類型:String, int, boolean, byte, char, double, float, long, short.

env
可以通過內嵌的 <env>元素給TestNG的單獨的虛擬機傳遞指定的環境變量。
要查閱<env> 元素屬性的詳細描述,請查看ant的exec任務的描述。

舉例:
Suite xml

  1. <testng classpathref="run.cp"  
  2.         outputDir="${testng.report.dir}"  
  3.         sourcedir="${test.src.dir}"  
  4.         haltOnfailure="true">  
  5.    
  6.    <xmlfileset dir="${test14.dir}" includes="testng.xml"/>  
  7. </testng>  
 

Class FileSet

<testng classpathref="run.cp"
        outputDir="${testng.report.dir}"
        haltOnFailure="true"M verbose="2">
    <classfileset dir="${test.build.dir}" includes="**/*.class" />
</testng>

5 - Test methods, Test classes and Test groups
5.1 - Test groups

TestNG容許執行復雜的測試方法分組。不僅可以申明方法屬於組,而且可以指定分組包含其他分組。
然後TestNG可以被調用,並被要求包含某些分組和排除其他的分組。
這將提供怎樣劃分測試的最大彈性,並且如果想運行兩個不同的測試裝置不需要重新編譯。

例如,非常普遍的需要至少兩個種類的測試

    * Check-in tests.  這些測試將在提交新代碼之前運行. 它們典型的被要求快速而且僅僅確認沒有基礎功能被破壞。 
    * Functional tests.  這些測試將覆蓋所有的軟件功能,並且必須運行至少1天,儘管理想的是連續運行.

代表性的,check-in測試是功能性測試的子集。TestNG容許用非常直接的方式說明這個。
例如: 可以這樣構造測試,申明完整的測試類屬於"functest"組,另外兩個方法屬於組"checkintest":

  1. public class Test1 {  
  2.   @Test(groups = { "functest""checkintest" })  
  3.   public void testMethod1() {  
  4.   }  
  5.   @Test(groups = {"functest""checkintest"} )  
  6.   public void testMethod2() {  
  7.   }  
  8.   @Test(groups = { "functest" })  
  9.   public void testMethod3() {  
  10.   }  
  11. }  
 

調用TestNG,使用

  1. <test name="Test1">  
  2.   <groups>  
  3.     <run>  
  4.       <include name="functest"/>  
  5.     </run>  
  6.   </groups>  
  7.   <classes>  
  8.     <class name="example1.Test1"/>  
  9.   </classes>  
  10. </test>  

將運行在類中的所有測試方法,如果使用checkintest調用則將只運行testMethod1()和testMethod2().

這裏由其他例子,這次使用正則表達式。假設某些測試方法可能無法在Linux上運行,測試將是類似如此:

  1. @Test  
  2. public class Test1 {  
  3.   @Test(groups = { "windows.checkintest" })   
  4.   public void testWindowsOnly() {  
  5.   }  
  6.   @Test(groups = {"linux.checkintest"} )  
  7.   public void testLinuxOnly() {  
  8.   }  
  9.   @Test(groups = { "windows.functest" )  
  10.   public void testWindowsToo() {  
  11.   }  
  12. }  
 

你可以使用下面的testng.xml文件只啓動Windows方法:

  1. <test name="Test1">  
  2.   <groups>  
  3.     <run>  
  4.       <include name="windows.*"/>  
  5.     </run>  
  6.   </groups>  
  7.   <classes>  
  8.     <class name="example1.Test1"/>  
  9.   </classes>  
  10. </test>  
 

注意:TestNG使用正則表達,而不是wildmats。注意這個差別。

Method groups
同樣可以包含或排除個別方法:

  1. <test name="Test1">  
  2.   <classes>  
  3.     <class name="example1.Test1">  
  4.       <methods>  
  5.         <include name=".*enabledTestMethod.*"/>  
  6.         <exclude name=".*brokenTestMethod.*"/>  
  7.       </methods>  
  8.      </class>  
  9.   </classes>  
  10. </test>  
 

這在需要使莫個單獨的方法失效而不想重新編譯時非常方便,但是不建議太多的使用這個機制,因爲這將可能破壞你的測試框架 如果你開始重構你的java代碼(標籤中使用的正則表達式可能不再匹配你的方法)
5.2 - Groups of groups

"functest" itself will contain the groups "windows" and "linux" while "checkintest will only contain "windows".  Here is how you would define this in your property file:
組可以包含其他組。這些組被稱爲"MetaGroups"。例如,你可能想定義一個"all"組,包括"checkintest"和"functest"。"functest"自身將包含組 "windows" 和 "linux",而"checkintest"將包含"windows".

  1. <test name="Regression1">  
  2.   <groups>  
  3.     <define name="functest">  
  4.       <include name="windows"/>  
  5.       <include name="linux"/>  
  6.     </define>  
  7.    
  8.     <define name="all">  
  9.       <include name="functest"/>  
  10.       <include name="checkintest"/>  
  11.     </define>  
  12.    
  13.     <run>  
  14.       <include name="all"/>  
  15.     </run>  
  16.   </groups>  
  17.    
  18.   <classes>  
  19.     <class name="test.sample.Test1"/>  
  20.   </classes>  
  21. </test>  
 

5.3 - Exclusion groups

TestNG 容許包含組也容許排除組.

例如,當由因爲最近的修改而臨時破壞的測試而又沒有時間去修復它們時非常有用。無論如何,你想要乾淨的運行功能性測試,因此你想要是這些測試失效,但是記住它們重新被激活。
一個簡單的解決這個問題的方法是創建一個稱爲"broken"的組並讓這些測試方法歸屬它。例如,在上面的例子中,我知道testMethod2() 現在被破壞了,所有我想關閉它:

  1. @Test(groups = {"checkintest""broken"} )  
  2. public void testMethod2() {  
  3. }  
 

現在我所想要做的只是在運行中排除這個組:

  1. <test name="Simple example">  
  2.   <groups>  
  3.     <run>  
  4.       <include name="checkintest"/>  
  5.       <exclude name="broken"/>  
  6.     </run>  
  7.   </groups>  
  8.    
  9.   <classes>  
  10.     <class name="example1.Test1"/>  
  11.   </classes>  
  12. </test>  
 

用這種方法,我將得到一個乾淨的測試運行,同時記錄了那些被破壞並想要後續修復的測試。
注意:你也可以通過使用在@Test and @Before/After annotations上的"enabled"屬性在個體的層面上關閉測試,

5.4 - Partial groups
你可以在類的級別上定義組,然後在方法的層次上添加組:

  1. @Test(groups = { "checkin-test" })  
  2. public class All {  
  3.   @Test(groups = { "func-test" )  
  4.   public void method1() { ... }  
  5.   public void method2() { ... }  
  6. }  
 

在這個類中,method2() 屬於組"checkin-test",在類的級別定義。而method1() 同時屬於 "checkin-test" 和 "func-test".
5.5 - Parameters

測試方法不要求是無參數的。你可以在每個測試方法上使用任意數量的參數,並指示testNG傳遞正確的參數。
有兩種方式用於設置參數:使用testng.xml或者編程式。

  5.5.1 - Parameters from testng.xml
如果你要爲你的參數使用簡單值,你可以在你的testng.xml中明確指定:

  1. @Parameters({ "first-name" })  
  2. @Test  
  3. public void testSingleString(String firstName) {  
  4.   System.out.println("Invoked testString " + firstName);  
  5.   assert "Cedric".equals(firstName);  
  6. }  

在這個代碼中,我們明確指定java方法的參數“firstName”應該接收名爲“first-name”xml參數的值。 這個xml參數在testng.xml中定義:


<suite name="My suite">
  <parameter name="first-name"  value="Cedric"/>
  <test name="Simple example">
  <--  -->
同樣的方法可以用於註解@Before/After和@Factory:

  1. @Parameters({ "datasource""jdbcDriver" })  
  2. @BeforeMethod  
  3. public void beforeTest(String ds, String driver) {  
  4.   m_dataSource = ;                              // look up the value of datasource  
  5.   m_jdbcDriver = driver;  
  6. }  

這次,兩個java參數ds和driver將分別接收被設置給屬性datasource和jdbc-driver的值。
參數可以通過可選註解來聲明爲可選:

@Parameters("db")
@Test
public void testNonExistentParameter(@Optional("mysql") String db) {  }
如果在testng.xml文件中沒有找到名爲"db"的參數,測試方法將接受在@Optional註解中指定的默認值:"mysql"
@Parameters 註解可以在下面位置使用:
    * 在任何有@Test, @Before/After或者@Factory註解的方法上
    * 在測試類的最多一個構造函數上。這種情況下,當TestNG需要實例化測試類時,他將調用這個特別的帶有初始化爲testng.xml中指定的值的參數的構造函數。這個特性可以被用於初始化類內部的值域爲將用於測試方法的值。
    注意:
        * xml參數被以在註解中出現的相同順序映射到java參數,如果參數數量不匹配testNG將發生錯誤。
        * 參數是有範圍的。在testng.xml中,你可以在<suite>標籤或者<test>標籤下聲明參數。如果兩個參數同名,在<test>標籤下定義的參數優先。非常適用於這樣的場合:需要指定一個應用於所有測試的參數,但是又希望在特定測試用覆蓋它的值。

  5.5.2 - Parameters with DataProviders

在testng.xml中指定參數,對於以下情況是不夠的:
    * 不使用testng.xml
    * 需要傳遞複雜參數,或者參數需要從java中創建(複雜對象,從屬性文件或者數據庫中讀取的對象)在這種情況下,你可以使用Data Provider來提供你測試需要的數值。Data Provider是類中的一個返回對象數組的數組的方法。這個方法帶有@DataProvider註解:

//這個方法將提供數據給任何聲明它的Data Provider名爲"test1"的測試方法

  1. @DataProvider(name = "test1")  
  2. public Object[][] createData1() {  
  3.  return new Object[][] {  
  4.    { "Cedric"new Integer(36) },  
  5.    { "Anne"new Integer(37)},  
  6.  };  
  7. }  
 

//這個方法聲明它的數據將由名爲"test1"的Data Provider提供

  1. @Test(dataProvider = "test1")  
  2. public void verifyData1(String n1, Integer n2) {  
  3.  System.out.println(n1 + " " + n2);  
  4. }  
 

將打印
    Cedric 36
    Anne 37 
@Test方法用dataProvider屬性來指定它的Data Provider。這個名字必須符合同一個類中用@DataProvider(name="...")註解的方法,它們要使用同一個匹配的名字。
默認,將在當前類或者它的基類中查找data provider。如果你想將data provider放置到另一個類中,需要將這個data provider方法設置爲靜態方法,並在dataProviderClass屬性中指定在哪個類中可以找到這個方法。

  1. public static class StaticProvider {  
  2.   @DataProvider(name = "create")  
  3.   public static Object[][] createData() {  
  4.     return new Object[][] {  
  5.       new Object[] { new Integer(42) }  
  6.     }  
  7.   }  
  8. }  
 

public class MyTest {
  @Test(dataProvider = "create", dataProviderClass = StaticProvider.class)
  public void test(Integer n) {
    // 
  }
}
Data Provider方法將返回下面兩個類型中的一種:
The Data Provider method can return one of the following two types:
    * 對象數組的數組(Object[][]) ,外圍數據的大小是測試方法將被調用的次數,而內層數組的大小和類型必須和測試方法的參數列表匹配。如同上面舉例說明的。
    * <Object[]>的Iterator,和Object[][]的唯一差別在於Iterator容許延遲創建測試數據。testNG將一個接一個的調用iterator,再用iterator返回的參數調用測試方法。如果有很多參數集合需要傳遞給方法而又不想一開始就創建所有參數,會非常有用。

Here is an example of this feature for both JDK 1.4 and JDK5 (note that the JDK 1.4 example does not use Generics):
這裏有一個同時適用於JDK 1.4和JDK5的例子(注意JDK 1.4的例子不使用註解):

  1. /** 
  2.  * @testng.data-provider name="test1" 
  3.  */  
  4. public Iterator createData() {  
  5.   return new MyIterator(DATA);  
  6. )  
  7. @DataProvider(name = "test1")  
  8. public Iterator createData() {  
  9.   return new MyIterator(DATA);  
  10. }  
 

如果將測試方法的第一個參數申明爲java.lang.reflect.Method,TestNG將使用這個第一個參數來傳遞當前測試方法。當多個測試方法使用同一個@DataProvider而需要依當前申請數據的方法而定來返回不同值時特別有用。
舉例說明,下面的代碼在@DataProvider中打印測試方法的名字:

  1. @DataProvider(name = "dp")  
  2. public Object[][] createData(Method m) {  
  3.   System.out.println(m.getName());  // print test method name  
  4.   return new Object[][] { new Object[] { "Cedric" }};  
  5. }  
  6. @Test(dataProvider = "dp")  
  7. public void test1(String s) {  
  8. }  
  9. @Test(dataProvider = "dp")  
  10. public void test2(String s) {  
  11. }  
 

將會顯示:
    test1
    test2

5.6 - Dependent methods

有些時候,你需要你的測試方法按照一個特定的順序被調用。這非常有用,比如:
    * 在運行更多測試方法前確認特定數量的測試方法調用完成並且成功
    * 初始化測試並希望這個初始化方法也作爲測試方法(被標記爲@Before/After的方法將不作爲最終報告的一部分)

爲了做到這點,需要使用@Test註解的dependsOnMethods屬性或者dependsOnGroups屬性。
有兩種依賴:
    * 強依賴。在運行你的測試方法前所有依賴方法必須運行並且成功。哪怕有一個依賴方法失敗,測試方法都不會被調用,在報告中將被標記爲SKIP。
    * 軟依賴。測試方法在依賴方法運行後總是會被運行,即使某些依賴方法失敗。對於只想確認測試方法是按照特定順序運行,而測試方法並不真正依賴其他方法是否成功的情況,非常有用。軟依賴通過在@Test註解中增加"alwaysRun=true"來實現。

這裏有一個強依賴的例子:

@Test
public void serverStartedOk() {}

@Test(dependsOnMethods = { "serverStartedOk" })
public void method1() {}

在這個例子中,method1()被申明依賴於方法serverStartedOk(),這保證serverStartedOk() 方法將總是首先被調用。
也可以讓方法依賴於完整的測試組:

@Test(groups = { "init" })
public void serverStartedOk() {}

@Test(groups = { "init" })
public void initEnvironment() {}

@Test(dependsOnGroups = { "init.* })
public void method1() {}

在這裏例子中,method1()被申明依賴於任何匹配正則表達式"init.*"的組,這保證了方法serverStartedOk()和initEnvironment()總是在method1()前被調用。

注意:前面說明說,在測試運行期間,屬於同一個組的方法的調用順序並不保證相同。如果一個方法的依賴失敗了,而且是強依賴(默認alwaysRun=false),這個方法將不被標記爲FAIL而是SKIP。被跳過的方法在最終的報告中報告(在HTML中用紅和綠之外的其他顏色),這很重要,因爲被跳過的方法並不一定是失敗。

dependsOnGroups和dependsOnMethods都接受正則表達式作爲參數。對於dependsOnMethods, 如果你依賴的方法巧合有多個重載的版本,所有裝載的方法都將被調用。如果你只想調用重載的方法中的一個,請使用dependsOnGroups。

有關方法依賴的更高級的例子,請參考本文檔,將使用繼承來提供一個優雅的解決方案來處理多重依賴的問題。

5.7 - Factories

工廠類容許你動態創建測試案例。例如,想象你需要創建一個測試方法,訪問一個web站點上的頁面很多次,而你希望用不同的值來調用它:


  1. public class TestWebServer {  
  2.   @Test(parameters = { "number-of-times" })  
  3.   public void accessPage(int numberOfTimes) {  
  4.     while (numberOfTimes-- > 0) {  
  5.      // access the web page  
  6.     }  
  7.   }  
  8. }  
 

testng.xml:

  1. <test name="T1">  
  2.   <parameter name="number-of-times" value="10"/>  
  3.   <class name"TestWebServer" />  
  4. </test>  
  5. <test name="T2">  
  6.   <parameter name="number-of-times" value="20"/>  
  7.   <class name"TestWebServer"/>  
  8. </test>  
  9. <test name="T3">  
  10.   <parameter name="number-of-times" value="30"/>  
  11.   <class name"TestWebServer"/>  
  12. </test>  
 

這種方式很快就會變的難於管理,所以作爲替換品,你可以使用factory:


  1. public class WebTestFactory {  
  2.   @Factory  
  3.   public Object[] createInstances() {  
  4.    Object[] result = new Object[10];   
  5.    for (int i = 0; i < 10; i++) {  
  6.       result[i] = new WebTest(i * 10);  
  7.     return result;  
  8.   }  
  9. }  
 

而新的測試類是這樣:

  1. public class WebTest {  
  2.   private int m_numberOfTimes;  
  3.   public WebTest(int numberOfTimes) {  
  4.     m_numberOfTimes = numberOfTimes;  
  5.   }  
  6.   @Test  
  7.   public void testServer() {  
  8.    for (int i = 0; i < m_numberOfTimes; i++) {  
  9.      // access the web page  
  10.     }  
  11.   }  
  12. }  
 

testng.xml只需要引用簡單引用這個包含factory方法的類,因爲測試實例將在運行時被創建。

<class name="WebTestFactory" />
工廠類將像@Test和@Before/After一樣接收參數,必須返回Object[]。返回的對象可以是任何類(不一定要求是和factory類一樣),並且他們甚至都不需要包含TestNG的註解(這種情況下他們將被testNG忽略)。

5.8 - Class level annotations

@Test註解可以放置在類上:

  1. @Test  
  2. public class Test1 {  
  3.   public void test1() {  
  4.   }  
  5.   public void test2() {  
  6.   }  
  7. }  
 

類級別註解的效果是將這個類的所有的public方法都變成測試方法,即使他們沒有被註解。還可以在需要增加屬性的方法上重複@Test註解。

例如:

  1. @Test  
  2. public class Test1 {  
  3.   public void test1() {  
  4.   }  
  5.   @Test(groups = "g1")  
  6.   public void test2() {  
  7.   }  
  8. }  
 

將方法test1()和test2()都變成測試方法,但是在此之上,test2()現在屬於組"g1".

5.9 - Parallel running and time-outs

可以通過使用parallel屬性要求TestNG在單獨的線程中運行測試。這個屬性可以在兩個值中取其一:

<suite name="My suite" parallel="methods" thread-count="5">

<suite name="My suite" parallel="tests" thread-count="5">
    * parallel="methods": TestNG將在單獨的線程中運行測試方法,除了那些依賴其他測試方法的,這些將在同一個線程中運行,以保證他們的執行順序。

    * parallel="tests": TestNG將在一個線程中運行所有在同一個<test>標籤中的測試方法,但是每個<test>標籤將在單獨的線程中運行。這種方式容許把所有不是線程安全的類分組到相同的<test>標籤中,保證他們將在相同的線程中運行,有利於TestNG使用儘可能多的線程來運行測試。

    此外,thread-count屬性容許指定運行時將分配多少線程。
    
    注意:@Test的屬性timeOut在併發和非併發模型下都可以工作。

    也可以指定@Test方法在不同的線程中被調用。可以使用threadPoolSize屬性來實現這樣的結果:

@Test(threadPoolSize = 3, invocationCount = 10,  timeOut = 10000)
public void testServer() {
}
在這個例子中,方法testServer將被3個不同線程調用10次。此外,10秒種的time-out屬性保證任何線程都不會長時間阻塞。


5.10 - Rerunning failed tests

套件中的測試失敗時,每次testNG都會在輸出目錄中創建一個名爲testng-failed.xml的文件。這個xml文件包含只重新運行這些失敗的測試方法的必要信息,容許只運行這些失敗的測試而不必運行全部測試。因此,一種典型的情況將是這樣:

java -classpath testng.jar;%CLASSPATH% org.testng.TestNG -d test-outputs testng.xml
java -classpath testng.jar;%CLASSPATH% org.testng.TestNG -d test-outputs test-outputs/testng-failed.xml
注意testng-failed.xml將包含所有必要的依賴方法,所以可以保證運行失敗的方法而不運行任何被跳過的(失敗)方法。

5.11 - JUnit tests

TestNG可以運行junit測試。所需要的只是在testng.classNames屬性中指定junit測試類,並設置testng.junit屬性爲true。

<test name="Test1"   junit="true">
  <classes>
    <!--  -->
這種情況下TestNG的行爲類似jnit:

    * 類中所有以test*開頭的方法將被運行。
    * 如果測試類中有方法setUp(), 將在每次測試方法調用前被執行。
    * 如果測試類中有方法tearDown(),將在每次測試方法調用後被執行。

5.12 - JDK 1.4

TestNG也可以在JDK1.4下工作。在這種情況下,需要使用發佈的jdk1.4的jar文件(名爲testng-...-jdk14.jar)。唯一的差別是在於註解,jdk1.4下使用流行的XDoclet javadoc註解語法:

public class SimpleTest {

  1.  /** 
  2.   * @testng.before-class = "true" 
  3.   */  
  4.   public void setUp() {  
  5.     // code that will be invoked when this test is instantiated  
  6.  }  
  7.  /** 
  8.   * @testng.test groups = "functest" dependsOnGroups = "group1,group2" 
  9.   */  
  10.   public void testItWorks() {  
  11.     // your test code  
  12.  }  
  13. }  

javadoc語法的規則非常簡潔,和jdk1.5註解的唯一差別是數組串數組需要特別寫成單獨的,逗號或空格分隔的字符串。雖然值周圍的雙引號是可選的,但還是建議在任何情況下都使用雙引號,以保證將來遷移到jdk1.5時可以比較容易。

同樣需要在<testng>的ant任務中指明sourcedir屬性(或者在命令行中使用-sourcedir),以便testNG可以找到你的測試文件的源代碼來解析javadoc註解。

這裏是jdk1.4和jdk5註解的語法對照表:

    (表格在blog中不好排版,不在這裏發了,詳細內容請參考官方文檔的原文:http://testng.org/doc/documentation-main.html#jdk-14。)

更多jdk1.4的支持範例,請參考發行包中的test-14文件夾,這裏包含全部的JDK 1.5測試對應的使用javadoc註解的內容。


5.13 - Running TestNG programmatically

在自己的程序中調用testNG也很簡單:

TestListenerAdapter tla = new TestListenerAdapter();
TestNG testng = new TestNG();
testng.setTestClasses(new Class[] { Run2.class });
testng.addListener(tla);
testng.run();

這個範例創建了一個TestNG對象並運行測試類Run2。還增加了一個TestListener。你可以使用適配器類org.testng.TestListenerAdapter或自己實現org.testng.ITestListener。這個接口包含多個回調方法,使得可以追蹤測試的開始,成功,失敗等等。

類似的,可以使用testng.xml文件調用TestNG或者自己創建一個虛擬的testng.xml文件。爲了做到這點,需要使用org.testng.xml包的類:XmlClass, XmlTest, 等等。每個類對應他們xml標籤。

例如,假設你想創建下面的虛擬文件:

<suite name="TmpSuite" >
  <test name="TmpTest" >
    <classes>
      <class name="test.failures.Child"  />
    <classes>
    </test>
</suite>
你將使用下面的代碼:

XmlSuite suite = new XmlSuite();
suite.setName("TmpSuite");

XmlTest test = new XmlTest(suite);
test.setName("TmpTest");
List<XmlClass> classes = new ArrayList<XmlClass>();
classes.add(new XmlClass("test.failures.Child"));
test.setXmlClasses(classes) ;
然後你可以將XmlSuite傳遞給TestNG:

List<XmlSuite> suites = new ArrayList<XmlSuite>();
suites.add(suite);
TestNG tng = new TestNG();
tng.setXmlSuites(suites);
tng.run();

完整的API請參考javadoc。


5.14 - BeanShell and advanced group selection

如果testng.xml中的<include>和<exclude>標籤還不足夠滿足你的需要,你可以使用BeanShell表達式來決定是否需要將一個特定的測試方法包含在測試操作中。只需要在<test>標籤下指定這個表達式:

  1. <test name="BeanShell test">  
  2.  <method-selectors>  
  3.    <method-selector>  
  4.      <mce:script language="beanshell"><!-- 
  5.        groups.containsKey("test1") 
  6.  --></mce:script>  
  7.    </method-selector>  
  8.  </method-selectors>  
  9. <!--  -->  

當發現testng.xml中有<script>標籤,TestNG將忽略當前<test>標籤中的以後的組和方法的<include>和<exclude>標籤:BeanShell表達式將是決定一個測試方法是否包含的唯一方法。

這裏有一些BeanShell腳本的額外信息:

    * 必須返回boolean值。除了這個約束,任何有效的BeanShell代碼都被容許.(例如,你可能想在工作日返回true而在週末返回false,這將容許你更加日期不同差異性的運行測試。

    * TestNG爲了便利定義了以下變量:

        java.lang.reflect.Method method:  當前測試方法
        org.testng.ITestNGMethod testngMethod:  當前測試方法的描述
        java.util.Map<String, String> groups:  當前測試方法所屬組的Map

    * 你可能需要在你的表達式前後增加CDATA聲明(如上面所示)以避免討厭的xml轉義字

發佈了10 篇原創文章 · 獲贊 3 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章