2.3 TestNG 注解
TestNG 和其他很多 Java 框架(如 JUnit、Spring 等)一样,使用了大量的注解。被不同注解修饰的类、方法具有不同的含义,本节对 TestNG 注解进行介绍,并按照使用场景把注解分成 4 类。
(1)前置条件和后置条件
把注解作为前置条件(或初始化操作)和后置条件(或清理操作)使用。
(2)数据驱动
TestNG 的特点之一是数据驱动,即测试用例和测试数据分离,以便维护和管理。
(3)测试用例
该分类只有一个@Test 注解。@Test 注解的作用是对测试用例进行控制,该注解中的方法有很多,后面会对常用方法进行介绍。
(4)监听器
该分类只有一个@Listeners 注解。监听器的作用是监控测试过程,如果采用默认监听器,则不需要任何配置;如果使用自定义监听器,则需要使用@Listeners 注解或 testng.xml 文件进行配置。由于篇幅所限,本章不对自定义监听器进行介绍,有兴趣的读者可以自行查阅相关资料。
2.3.1 前置条件和后置条件
先来看看各注解的含义。
@BeforeSuite:在该 Suite 的所有 Test 都未运行之前运行。
@AfterSuite:在该 Suite 的所有 Test 都运行之后运行。
一个 Suite 对应一个顶级模块,比如一个软件项目分为 4 个模块,那么每个模块就是一个 Suite。一般结合 testng.xml 文件中的<;suite>;或<;suite-files>;标签进行使用。
@BeforeTest:在该 Test 的所有 Class 都未运行之前运行。
@AfterTest:在该 Test 的所有 Class 都运行之后运行。
一个 Test 对应一个子模块,一般结合 testng.xml 文件中的<;test>;标签进行使用。
@BeforeClass:在该 Class 的所有@Test 方法都未运行之前运行。
@AfterClass:在该 Class 的所有@Test 方法都运行之后运行。
一个 Class 对应一个 Java 类,在该 Java 类中,用@BeforeClass(或@AfterClass)修饰的方法会在该 Class 的所有@Test 方法都运行之前(或之后)运行。
@BeforeMethod:在该 Class 的每个@Test 方法运行之前运行。
@AfterMethod:在该 Class 的每个@Test 方法运行之后运行。
一个 Method 对应一个 Java 方法,在 Java 类中用@BeforeMethod(或@AfterMethod)修饰的方法会在该 Class 的每个@Test 方法 运行之前(或之后)运行。
@BeforeGroups:在该 Class 第一个分组的@Test 方法运行之前运行。
@AfterGroups:在该 Class 最后一个分组的@Test 方法运行之后运行。
Group 的控制粒度介于 Class 和 Method 之间,一个 Class 可以包含多个 Group,一个 Group 可以包含多个 Method。
只看文字是很生硬的,下面通过例子来说明以上注解。删除 FirstClassTest 中的内容,输入以下代码:
保存代码,在「FirstClassTest.java」上用鼠标右击,从弹出的快捷菜单中选择「Run As → TestNG Test」选项,此时 Eclipse 的控制台输出如下:
下面对运行结果进行说明。
① 可以看出@BeforeSuite、@AfterSuite、@BeforeTest、@AfterTest、@BeforeClass 和@AfterClass 控制测试执行的粒度是不同的,即 Suite > Test > Class
② 一个测试用例(@Test 修饰的 Java 方法)可以属于多个分组,比如上面示例的 testCase4。当多个分组都设置了对应的@BeforeGroups 和@AfterGroups 注解时,执行顺序是 Before Group1→Before Group2→After Group2→After Group1
③@BeforeMethod 和@AfterMethod 共执行了 4 次,因为有 4 个测试用例
2.3.2 数据驱动
TestNG 做数据驱动时使用了@DataProvider 和@Parameters 注解,后者需要和 testng.xml 文件配合。举一个登录的场景,每种不同的输入都对应了不同的提示。
删除 FirstClassTest 中的内容,输入以下代码:
package cn.edu.bjut.testng; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class FirstClassTest3 { @Test(dataProvider = "data") public void testCase1(String username ,String password ,String prompt) { System.out.println("如果输入:" + username +"、" + password +",提示" + prompt); } @DataProvider(name = "data") public Object[][] dataProvider1(){ return new Object[][] { new Object[] {"空账号","正确密码","账号不能为空!"}, new Object[] {"正确账号","空密码","密码不能为空!"}, new Object[] {"正确账号","正确密码","登陆成功!"} }; } }
保存代码,在 FirstClassTest.java 上用鼠标右击,从弹出的快捷菜单中选择「Run As → TestNG Test」选项,此时 Eclipse 的控制台输出如下:
被@DataProvider 修饰的 Java 方法称为数据提供者,该方法返回一个对象二维数组。如果一个测试用例需要该数据,那么就通过@Test 注解的 dataProvider 属性传入数据提供者的名称name。
2.3.3 测试用例
@Test 注解的方法很多,前面已经介绍过 groups 和 dataProvider 了,下面再介绍几种常用的。
删除 FirstClassTest 中的内容,输入以下代码:
package cn.edu.bjut.testng; import org.testng.annotations.Test; public class FirstClassTest4 { @Test(description = "测试用例1") public void testCase1() { System.out.println("testCase1"); } @Test(priority = 2) public void testCase2() { System.out.println("testCase2"); } @Test(priority = 1) public void testCase3() { System.out.println("testCase3"); } @Test() public void testCase4() { System.out.println("testCase4"); throw new RuntimeException("testCase4运行异常!"); } @Test(groups = { "myGroup" }) public void testCase5() { System.out.println("testCase5"); throw new RuntimeException("testCase5运行异常!"); } @Test(enabled = false) public void testCase6() { System.out.println("testCase6"); } @Test(dependsOnMethods = {"testCase4"},dependsOnGroups = {"myGroup"},alwaysRun = true) public void testCase7() { System.out.println("testCase7"); } }
保存代码,在「FirstClassTest.java」上用鼠标右击,从弹出的快捷菜单中选择「Run As → TestNG Test」选项,此时 Eclipse 的控制台输出如下:
下面对运行结果进行说明。
①description 代表测试用例描述,控制台会打印输出该描述。
②priority 代表优先级,数字越小,优先级越高,默认值为 0。testCase2 的 priority 值为 2,会最后一个执行;testCase3 的 priority 值为 1,会倒数第二个执行。如果级别一样,则执行顺序默认按方法名排序。
③enabled 的默认值为 true,代表启用。当 enabled 的值为 false 时,表示禁用,因此 testCase6 并未执行。
④testCase4 和 testCase5 都抛出了运行时异常,因此执行失败。
⑤dependsOnMethods 代表依赖一个或多个方法,dependsOnGroups 代表依赖一个或多个分组。一旦被依赖的测试用例执行失败,则 TestNG 将跳过该测试用例。但没有跳过 testCase7,原因是 testCase7 加了 alwaysRun 方法,并将值设为 true,代表始终执行,在默认情况下,该值为 false。建议尽量不要使用 dependsOnMethods 和 dependsOnGroups,因为违背了测试用例需要解耦的原则。