在自动化测试中使用TestNG【第 2 章 TestNG语法 2.3TestNG注解】

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 个测试用例


GroupsOnClass1
@Test(groups = "stu")
public class GroupsOnClass1 {

    public void stu1(){
        System.out.println("GroupsOnClass1中的stu1111运行");
    }

    public void stu2(){
        System.out.println("GroupsOnClass1中的stu2222运行");
    }
}
GroupsOnClass2
@Test(groups = "stu")
public class GroupsOnClass2 {
    public void stu1(){
        System.out.println("GroupsOnClass2中的stu1111运行");
    }

    public void stu2(){
        System.out.println("GroupsOnClass2中的stu2222运行");
    }

}
GroupsOnClass3
@Test(groups = "teacher")
public class GroupsOnClass3 {

    public void teacher1(){
        System.out.println("GroupsOnClass3中的teacher1运行");
    }

    public void teacher2(){
        System.out.println("GroupsOnClass3中的teacher2运行");
    }

}

groupsOnClass.xml

<?xml version="1.0" encoding="UTF-8" ?>

<suite name="suitename">
    <test name="runAll">
        <classes>
            <class name="com.course.testng.groups.GroupsOnClass1"/>
            <class name="com.course.testng.groups.GroupsOnClass2"/>
            <class name="com.course.testng.groups.GroupsOnClass3"/>
        </classes>

    </test>

    <test name="onlyRunStu">
        <groups>
            <run>
                <include name="stu"/>
            </run>

        </groups>

        <classes>
            <class name="com.course.testng.groups.GroupsOnClass1"/>
            <class name="com.course.testng.groups.GroupsOnClass2"/>
            <class name="com.course.testng.groups.GroupsOnClass3"/>
        </classes>

    </test>



</suite>
View Code
GroupsOnMethod

public class GroupsOnMethod {

    @Test(groups = "server")
    public void test1(){
        System.out.println("这是服务端组的测试方法11111");
    }

    @Test(groups = "server")
    public void test2(){
        System.out.println("这是服务端组的测试方法2222");
    }

    @Test(groups = "client")
    public void test3(){
        System.out.println("这是客户端组的测试方法33333");
    }
    @Test(groups = "client")
    public void test4(){
        System.out.println("这是客户端组的测试方法4444");
    }

    @BeforeGroups("server")
    public void beforeGroupsOnServer(){
        System.out.println("这是服务端组运行之前运行的方法");
    }

    @AfterGroups("server")
    public void afterGroupsOnServer(){
        System.out.println("这是服务端组运行之后运行的方法!!!!!");
    }

    @BeforeGroups("client")
    public void beforeGroupsOnClient(){
        System.out.println("这是客户端组运行之前运行的方法");
    }

    @AfterGroups("client")
    public void afterGroupsOnClient(){
        System.out.println("这是客户端组运行之后运行的方法!!!!!");
    }


}
View Code
DependTest
public class DependTest {

    @Test
    public void test1(){
        System.out.println("test1 run");
        throw new RuntimeException();

    }

    @Test(dependsOnMethods = {"test1"})
    public void test2(){
        System.out.println("test2 run");
    }

}

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,因为违背了测试用例需要解耦的原则

posted @ 2020-12-27 22:15  Marlon康  阅读(191)  评论(0编辑  收藏  举报