5.7 - 工厂
工厂允许你动态的创建测试。例如,假设你需要创建一个测试方法,并用它来多次访问一个web页面,而且每次都带有不同的参数:
public class TestWebServer {testng.xml:
@Test(parameters = { "number-of-times" })
public void accessPage(int numberOfTimes) {
while (numberOfTimes-- > 0) {
// access the web page
}
}
}
<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 只需要引用包含工厂方法的类,而测试实例自己会在运行时创建:
<class name="WebTestFactory" />
工厂方法可以接受诸如 @Test 和 @Before/After 所标记的参数,并且会返回 Object[]。这些返回的对象可以是任何类(不一定是跟工厂方法相同的类),并且他们甚至都不需要TestNG注解(在例子中会被TestNG忽略掉)
5.8 - 类级注解
通常 @Test 也可以用来标注类,而不仅仅是方法:@Test处于类级的 @Test 会使得类中所有的public方法成为测试方法,而不管他们是否已经被标注。当然,你仍然可以用 @Test 注解重复标注测试方法,特别是要为其添加一些特别的属性时。
public class Test1 {
public void test1() {
}
public void test2() {
}
}
例如:
@Test上例中 test1() 和 test2() 都被处理,不过在此之上 test2() 现在还属于组 "g1"。
public class Test1 {
public void test1() {
}
@Test(groups = "g1")
public void test2() {
}
}
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 方法在不同的线程中被调用。你可以使用属性 threadPoolSize 来实现:注意:@Test 中的属性 timeOut 可以工作在并行和非并行两种模式下。
@Test(threadPoolSize = 3, invocationCount = 10, timeOut = 10000)上例中,方法 testServer 会在3个线程中调用10次。此外,10秒钟的超时设定也保证了这三个线程中的任何一个都永远不会阻塞当前被调用的线程。
public void testServer() {
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 注解的说明。