5.7 - 工廠
工廠允許你動態建立測試。例如,假設你需要建立一個測試方法,並用它來多次訪問一個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>
參數一旦多起來,就難以管理了,所以應該使用工廠來做:
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" />
Factory 方法可以接受諸如 @Test 和 @Before/After 所標記的參數,並且會返回 Object[]。這些返回的對象可以是任何類(不一定是跟Factory 方法相同的類),並且他們甚至都不需要TestNG註解(在例子中會被TestNG忽略掉)
5.8 - 類級註解
通常 @Test 也可以用來標註類,而不僅僅是方法:
@Test
public class Test1 {
public void test1() {
}
public void test2() {
}
}
處於類級的 @Test 會使得類中所有的public方法成為測試方法,而不管他們是否已經被標註。當然,你仍然可以用 @Test 註解重複標註測試方法,特別是要為其添加一些特別的屬性時。
例如:
@Test
public class Test1 {
public void test1() {
}
@Test(groups = "g1")
public void test2() {
}
}
上例中 test1() 和 test2() 都被處理,不過在此之上 test2() 現在還屬於組 "g1"。
5.9 - 並行運行於逾時
你可以通過在suite標籤中使用 parallel 屬性來讓測試方法運行在不同的線程中。這個屬性可以帶有如下這樣的值:
<suite name="My suite" parallel="methods" thread-count="5">
<suite name="My suite" parallel="tests" thread-count="5">
<suite name="My suite" parallel="classes" thread-count="5">
- parallel="methods": TestNG 會在不同的線程中運行測試方法,除非那些互相依賴的方法。那些相互依賴的方法會運行在同一個線程中,並且遵照其執行順序。
- parallel="tests": TestNG 會在相同的線程中運行相同的<test>標記下的所有方法,但是每個<test>標籤中的所有方法會運行在不同的線程中。這樣就允許你把所有非安全執行緒的類分組到同一個<test>標籤下,並且使其可以利用TestNG多線程的特性的同時,讓這些類運行在相同的線程中。
- parallel="classes": TestNG 會在相同線程中相同類中的運行所有的方法,但是每個類都會用不同的線程運行。
此外,屬性 thread-count 允許你為當前的執行指定可以啟動並執行線程數量。
注意:@Test 中的屬性 timeOut 可以工作在並行和非並行兩種模式下。
你也可以指定 @Test 方法在不同的線程中被調用。你可以使用屬性 threadPoolSize 來實現:
@Test(threadPoolSize = 3, invocationCount = 10, timeOut = 10000)
public void testServer() {
上例中,方法 testServer 會在3個線程中調用10次。此外,10秒鐘的逾時設定也保證了這三個線程中的任何一個都永遠不會阻塞當前被調用的線程。
5.10 - 再次運行失敗的測試
每次測試suite出現失敗的測試,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 已經包含了所有失敗方法運行時需要的依賴,所以完全可以保證上次失敗的方法不會出現任何 SKIP。
5.11 - JUnit測試
TestNG 能夠運行 JUnit 測試。所有要做的工作就是在 testng.classNames 屬性中設定要啟動並執行JUnit測試類別,並且把 testng.junit 屬性設定為true:
<test name="Test1" junit="true">
<classes>
<!-- ... -->
TestNG 在這種情況下所表現的行為與 JUnit 相似:
- 所有類中要啟動並執行測試方法由 test* 開頭
- 如果類中有 setUp() 方法,則其會在每個測試方法執行前被調用
- 如果類中有 tearDown() 方法,則其會在每個測試方法之後被調用
- 如果測試類別包含 suite() 方法,則所有的被這個方法返回的測試類別都會被調用
5.12 - JDK 1.4
TestNG 也可以工作在 JDK 1.4 下。你需要使用 JDK 1.4 jar ,在發行版中可以找到( 名為testng-...-jdk14.jar)。唯一的不同就是註解的方式,它使用的流行的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 文法的規則是相當的直接,並且與JDK 1.5 註解唯一的不同就在於字串數組被表示為單個逗號或者空格分隔的形式。然而,用雙引號標註值時可選的,不過我極力推薦你使用雙引號,以便以後 遷移到JDK 1.5 會更容易些。
你也需要在使用ant任務中在 <testng> 標記中指定 sourcedir 屬性 (或 -sourcedir 在命令列下),這樣TestNG 就能夠按順序找到測試檔案,並且解析JavaDoc註解。
下標就是比較 JDK 1.4 和 JDK 5 註解的異同。
| JDK 5 |
JDK 1.4 |
@Test(groups = { "a", "b" }, dependsOnMethods = { "m1" }) |
/** * @testng.test groups = "a b" * dependsOnMethods = "m1" */
|
@AfterMethod(alwaysRun = true)
|
/** * @testng.before-method alwaysRun = "true" */
|
| @Parameters({ "first-name", "last-name" }) |
/** * @testng.parameters value = "first-name last-name" */
|
@Factory @Parameters({ "first-name", "last-name"}) |
/** * @testng.factory * @testng.parameters value = "first-name last-name" */
|
| @DataProvider(name = "test1") |
/** * @testng.data-provider name="test1" */ |
關於 TestNG's JDK 1.4 的例子和支援,請參看發行版中的 test-14/ 目錄,其中包含了完整的 JDK 1.5 被映射到 JavaDoc 註解的說明。