1. 介紹
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文件的一個例子:
- <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
- <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>
你可以指定包名替代類名:
- <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
- <suite name="Suite1" verbose="1" >
- <test name="Regression1" >
- <packages>
- <package name="test.sample" />
- </packages>
- </test>
- </suite>
在這個例子中,TestNG將在包test.sample中查找所有的類,並只保留帶有TestNG annotation的類。
你同樣可以指定包含或不包含的組和方法:
- <test name="Regression1">
- <groups>
- <run>
- <exclude name="brokenTests" />
- <include name="checkinTests" />
- </run>
- </groups>
- <classes>
- <class name="test.IndividualMethodsTest">
- <methods>
- <include name="testMethod" />
- </methods>
- </class>
- </classes>
- </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>元素來指定類需要的系統屬性。在測試的執行期間虛擬機可以獲取這些屬性。 這個元素的屬性和環境變量相同。
- <testng>
- <sysproperty key="basedir" value="${basedir}"/>
- <!-- ... -->
- </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
- <testng classpathref="run.cp"
- outputDir="${testng.report.dir}"
- sourcedir="${test.src.dir}"
- haltOnfailure="true">
- <xmlfileset dir="${test14.dir}" includes="testng.xml"/>
- </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":
- public class Test1 {
- @Test(groups = { "functest", "checkintest" })
- public void testMethod1() {
- }
- @Test(groups = {"functest", "checkintest"} )
- public void testMethod2() {
- }
- @Test(groups = { "functest" })
- public void testMethod3() {
- }
- }
調用TestNG,使用
- <test name="Test1">
- <groups>
- <run>
- <include name="functest"/>
- </run>
- </groups>
- <classes>
- <class name="example1.Test1"/>
- </classes>
- </test>
將運行在類中的所有測試方法,如果使用checkintest調用則將只運行testMethod1()和testMethod2().
這里由其他例子,這次使用正則表達式。假設某些測試方法可能無法在Linux上運行,測試將是類似如此:
- @Test
- public class Test1 {
- @Test(groups = { "windows.checkintest" })
- public void testWindowsOnly() {
- }
- @Test(groups = {"linux.checkintest"} )
- public void testLinuxOnly() {
- }
- @Test(groups = { "windows.functest" )
- public void testWindowsToo() {
- }
- }
你可以使用下面的testng.xml文件只啟動Windows方法:
- <test name="Test1">
- <groups>
- <run>
- <include name="windows.*"/>
- </run>
- </groups>
- <classes>
- <class name="example1.Test1"/>
- </classes>
- </test>
注意:TestNG使用正則表達,而不是wildmats。注意這個差別。
Method groups
同樣可以包含或排除個別方法:
- <test name="Test1">
- <classes>
- <class name="example1.Test1">
- <methods>
- <include name=".*enabledTestMethod.*"/>
- <exclude name=".*brokenTestMethod.*"/>
- </methods>
- </class>
- </classes>
- </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".
- <test name="Regression1">
- <groups>
- <define name="functest">
- <include name="windows"/>
- <include name="linux"/>
- </define>
- <define name="all">
- <include name="functest"/>
- <include name="checkintest"/>
- </define>
- <run>
- <include name="all"/>
- </run>
- </groups>
- <classes>
- <class name="test.sample.Test1"/>
- </classes>
- </test>
5.3 - Exclusion groups
TestNG 容許包含組也容許排除組.
例如,當由因為最近的修改而臨時破壞的測試而又沒有時間去修復它們時非常有用。無論如何,你想要干凈的運行功能性測試,因此你想要是這些測試失效,但是記住它們重新被激活。
一個簡單的解決這個問題的方法是創建一個稱為"broken"的組並讓這些測試方法歸屬它。例如,在上面的例子中,我知道testMethod2() 現在被破壞了,所有我想關閉它:
- @Test(groups = {"checkintest", "broken"} )
- public void testMethod2() {
- }
現在我所想要做的只是在運行中排除這個組:
- <test name="Simple example">
- <groups>
- <run>
- <include name="checkintest"/>
- <exclude name="broken"/>
- </run>
- </groups>
- <classes>
- <class name="example1.Test1"/>
- </classes>
- </test>
用這種方法,我將得到一個干凈的測試運行,同時記錄了那些被破壞並想要后續修復的測試。
注意:你也可以通過使用在@Test and @Before/After annotations上的"enabled"屬性在個體的層面上關閉測試,
5.4 - Partial groups
你可以在類的級別上定義組,然后在方法的層次上添加組:
- @Test(groups = { "checkin-test" })
- public class All {
- @Test(groups = { "func-test" )
- public void method1() { ... }
- public void method2() { ... }
- }
在這個類中,method2() 屬於組"checkin-test",在類的級別定義。而method1() 同時屬於 "checkin-test" 和 "func-test".
5.5 - Parameters
測試方法不要求是無參數的。你可以在每個測試方法上使用任意數量的參數,並指示testNG傳遞正確的參數。
有兩種方式用於設置參數:使用testng.xml或者編程式。
5.5.1 - Parameters from testng.xml
如果你要為你的參數使用簡單值,你可以在你的testng.xml中明確指定:
- @Parameters({ "first-name" })
- @Test
- public void testSingleString(String firstName) {
- System.out.println("Invoked testString " + firstName);
- assert "Cedric".equals(firstName);
- }
在這個代碼中,我們明確指定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:
- @Parameters({ "datasource", "jdbcDriver" })
- @BeforeMethod
- public void beforeTest(String ds, String driver) {
- m_dataSource = ; // look up the value of datasource
- m_jdbcDriver = driver;
- }
這次,兩個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"的測試方法
- @DataProvider(name = "test1")
- public Object[][] createData1() {
- return new Object[][] {
- { "Cedric", new Integer(36) },
- { "Anne", new Integer(37)},
- };
- }
//這個方法聲明它的數據將由名為"test1"的Data Provider提供
- @Test(dataProvider = "test1")
- public void verifyData1(String n1, Integer n2) {
- System.out.println(n1 + " " + n2);
- }
將打印
Cedric 36
Anne 37
@Test方法用dataProvider屬性來指定它的Data Provider。這個名字必須符合同一個類中用@DataProvider(name="...")注解的方法,它們要使用同一個匹配的名字。
默認,將在當前類或者它的基類中查找data provider。如果你想將data provider放置到另一個類中,需要將這個data provider方法設置為靜態方法,並在dataProviderClass屬性中指定在哪個類中可以找到這個方法。
- public static class StaticProvider {
- @DataProvider(name = "create")
- public static Object[][] createData() {
- return new Object[][] {
- new Object[] { new Integer(42) }
- }
- }
- }
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的例子不使用注解):
- /**
- * @testng.data-provider name="test1"
- */
- public Iterator createData() {
- return new MyIterator(DATA);
- )
- @DataProvider(name = "test1")
- public Iterator createData() {
- return new MyIterator(DATA);
- }
如果將測試方法的第一個參數申明為java.lang.reflect.Method,TestNG將使用這個第一個參數來傳遞當前測試方法。當多個測試方法使用同一個@DataProvider而需要依當前申請數據的方法而定來返回不同值時特別有用。
舉例說明,下面的代碼在@DataProvider中打印測試方法的名字:
- @DataProvider(name = "dp")
- public Object[][] createData(Method m) {
- System.out.println(m.getName()); // print test method name
- return new Object[][] { new Object[] { "Cedric" }};
- }
- @Test(dataProvider = "dp")
- public void test1(String s) {
- }
- @Test(dataProvider = "dp")
- public void test2(String s) {
- }
將會顯示:
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站點上的頁面很多次,而你希望用不同的值來調用它:
- public class TestWebServer {
- @Test(parameters = { "number-of-times" })
- public void accessPage(int numberOfTimes) {
- while (numberOfTimes-- > 0) {
- // access the web page
- }
- }
- }
testng.xml:
- <test name="T1">
- <parameter name="number-of-times" value="10"/>
- <class name= "TestWebServer" />
- </test>
- <test name="T2">
- <parameter name="number-of-times" value="20"/>
- <class name= "TestWebServer"/>
- </test>
- <test name="T3">
- <parameter name="number-of-times" value="30"/>
- <class name= "TestWebServer"/>
- </test>
這種方式很快就會變的難於管理,所以作為替換品,你可以使用factory:
- public class WebTestFactory {
- @Factory
- public Object[] createInstances() {
- Object[] result = new Object[10];
- for (int i = 0; i < 10; i++) {
- result[i] = new WebTest(i * 10);
- return result;
- }
- }
而新的測試類是這樣:
- public class WebTest {
- private int m_numberOfTimes;
- public WebTest(int numberOfTimes) {
- m_numberOfTimes = numberOfTimes;
- }
- @Test
- public void testServer() {
- for (int i = 0; i < m_numberOfTimes; i++) {
- // access the web page
- }
- }
- }
testng.xml只需要引用簡單引用這個包含factory方法的類,因為測試實例將在運行時被創建。
<class name="WebTestFactory" />
工廠類將像@Test和@Before/After一樣接收參數,必須返回Object[]。返回的對象可以是任何類(不一定要求是和factory類一樣),並且他們甚至都不需要包含TestNG的注解(這種情況下他們將被testNG忽略)。
5.8 - Class level annotations
@Test注解可以放置在類上:
- @Test
- public class Test1 {
- public void test1() {
- }
- public void test2() {
- }
- }
類級別注解的效果是將這個類的所有的public方法都變成測試方法,即使他們沒有被注解。還可以在需要增加屬性的方法上重復@Test注解。
例如:
- @Test
- public class Test1 {
- public void test1() {
- }
- @Test(groups = "g1")
- public void test2() {
- }
- }
將方法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 {
- /**
- * @testng.before-class = "true"
- */
- public void setUp() {
- // code that will be invoked when this test is instantiated
- }
- /**
- * @testng.test groups = "functest" dependsOnGroups = "group1,group2"
- */
- public void testItWorks() {
- // your test code
- }
- }
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>標簽下指定這個表達式:
- <test name="BeanShell test">
- <method-selectors>
- <method-selector>
- <mce:script language="beanshell"><!--
- groups.containsKey("test1")
- --></mce:script>
- </method-selector>
- </method-selectors>
- <!-- -->
當發現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轉義字符