testng:Java界功能强大的单元测试框架

文章目录

一、简介

官方文档:https://testng.org/

TestNG(Test Next Generation)是 Java 生态中功能强大、灵活度高的自动化测试框架,专为解决单元测试、集成测试、功能测试等全场景测试需求设计,弥补了 JUnit 早期版本的局限性(如缺乏分组、并行执行、灵活参数化等)。

二、使用

1、环境

jdk8,并且测试类一定要在src/test/目录下,创建java、resources文件夹

xml 复制代码
<dependencies>
    <!-- TestNG 核心依赖 -->
    <dependency>
        <groupId>org.testng</groupId>
        <artifactId>testng</artifactId>
        <version>7.5</version>
        <scope>test</scope> <!-- 仅测试代码生效 -->
    </dependency>
    <!-- 可选:日志依赖(便于调试) -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>2.0.7</version>
        <scope>test</scope>
    </dependency>
</dependencies>

<!-- 可选:Maven Surefire 插件(支持通过命令行运行 TestNG) -->
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>3.1.2</version>
            <configuration>
                <!-- 指定 TestNG 配置文件(后续会讲) -->
                <suiteXmlFiles>
                    <suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
                </suiteXmlFiles>
            </configuration>
        </plugin>
    </plugins>
</build>

2、TestNG 生命周期

TestNG 的测试生命周期分为 3 个层级(套件级 → 测试组级 → 测试方法级),注解按固定顺序执行,核心是"先初始化(BeforeXXX),后执行测试(@Test),最后清理(AfterXXX)"。

1.套件级(Suite):@BeforeSuite → 所有测试组/测试类执行前 → @AfterSuite(整个套件仅执行 1 次,适合全局初始化,如启动数据库、配置文件加载);

2.测试组级(Test):@BeforeTest → 某一组测试类执行前 → @AfterTest(按 XML 中 <test> 标签分组,每组执行 1 次);

3.测试类级(Class):@BeforeClass → 单个测试类执行前 → @AfterClass(每个测试类执行 1 次,适合类级初始化,如创建对象);

4.测试方法级(Method):@BeforeMethod → 每个 @Test 方法执行前 → @AfterMethod(每个测试方法执行 1 次,适合方法级清理,如重置数据);

5.测试方法(Test Method):被 @Test 注解的方法(核心执行单元)。

java 复制代码
import org.testng.annotations.*;

public class LifeCycleTest {
    // 套件级初始化(全局1次)
    @BeforeSuite
    public void beforeSuite() {
        System.out.println("1. @BeforeSuite:套件执行前");
    }

    // 测试组级初始化(每组1次)
    @BeforeTest
    public void beforeTest() {
        System.out.println("2. @BeforeTest:测试组执行前");
    }

    // 测试类级初始化(每个类1次)
    @BeforeClass
    public void beforeClass() {
        System.out.println("3. @BeforeClass:测试类执行前");
    }

    // 测试方法级初始化(每个方法1次)
    @BeforeMethod
    public void beforeMethod() {
        System.out.println("4. @BeforeMethod:测试方法执行前");
    }

    @Test
    public void test1() {
        System.out.println("5. 执行测试方法:test1");
    }

    @Test
    public void test2() {
        System.out.println("5. 执行测试方法:test2");
    }

    // 测试方法级清理(每个方法1次)
    @AfterMethod
    public void afterMethod() {
        System.out.println("6. @AfterMethod:测试方法执行后");
    }

    // 测试类级清理(每个类1次)
    @AfterClass
    public void afterClass() {
        System.out.println("7. @AfterClass:测试类执行后");
    }

    // 测试组级清理(每组1次)
    @AfterTest
    public void afterTest() {
        System.out.println("8. @AfterTest:测试组执行后");
    }

    // 套件级清理(全局1次)
    @AfterSuite
    public void afterSuite() {
        System.out.println("9. @AfterSuite:套件执行后");
    }
}
java 复制代码
执行结果顺序:严格按编号 1-9 执行,`@BeforeMethod` 和 `@AfterMethod` 会随每个 `@Test` 方法重复执行。
1. @BeforeSuite:套件执行前
2. @BeforeTest:测试组执行前
3. @BeforeClass:测试类执行前
4. @BeforeMethod:测试方法执行前
5. 执行测试方法:test1
6. @AfterMethod:测试方法执行后
4. @BeforeMethod:测试方法执行前
5. 执行测试方法:test2
6. @AfterMethod:测试方法执行后
7. @AfterClass:测试类执行后
8. @AfterTest:测试组执行后
9. @AfterSuite:套件执行后

3、核心注解全解析

注解 作用范围 执行时机 常用场景
@Test 方法 标记测试方法(核心) 定义测试逻辑,可配置分组、依赖、超时等
@BeforeSuite 套件 整个测试套件执行前(1次) 全局初始化(加载配置、启动服务)
@AfterSuite 套件 整个测试套件执行后(1次) 全局清理(关闭服务、释放资源)
@BeforeTest 测试组 某组测试类执行前(1次/组) 组内初始化(如创建测试数据)
@AfterTest 测试组 某组测试类执行后(1次/组) 组内清理(如删除测试数据)
@BeforeClass 测试类 单个测试类执行前(1次/类) 类级初始化(创建对象、连接数据库)
@AfterClass 测试类 单个测试类执行后(1次/类) 类级清理(关闭数据库连接)
@BeforeMethod 测试方法 每个 @Test 方法执行前(1次/方法) 方法级初始化(重置参数、清空缓存)
@AfterMethod 测试方法 每个 @Test 方法执行后(1次/方法) 方法级清理(恢复测试环境)
@Parameters 方法 为测试方法注入参数(从 XML 配置获取) 简单参数化(如环境地址、用户名)
@DataProvider 方法 提供多组测试数据(返回 Object[ ][ ]) 复杂参数化(多组入参、动态数据)
@Factory 方法 动态创建测试类实例 批量生成测试对象(如多环境测试)
@Listeners 类/方法 注册测试监听器(监听测试生命周期事件) 自定义报告、失败重试、日志记录
@Ignore 类/方法 忽略当前测试类/方法 暂不执行的用例(如未完成的功能)

4、简单使用入门

(1)编写被测试类(业务逻辑)

java 复制代码
// 被测试的业务类:计算器
public class Calculator {
    // 加法
    public int add(int a, int b) {
        return a + b;
    }

    // 减法(故意写个bug:返回 a - b + 1,用于测试失败场景)
    public int subtract(int a, int b) {
        return a - b + 1; // 错误逻辑
    }
}

(2)编写 TestNG 测试类

测试类通常与被测试类同名+Test:

java 复制代码
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class CalculatorTest {
    // 声明被测试对象
    private Calculator calculator;

    // 类级初始化:创建计算器实例(仅执行1次)
    @BeforeClass
    public void initCalculator() {
        calculator = new Calculator();
        System.out.println("初始化计算器完成");
    }

    // 测试加法(成功场景)
    @Test(description = "测试加法功能", priority = 1) // priority:执行优先级(数字越小越先执行)
    public void testAdd() {
        int result = calculator.add(2, 3);
        // 断言:验证结果是否等于预期(5)
        Assert.assertEquals(result, 5, "加法计算错误!");
        System.out.println("加法测试执行完成");
    }

    // 测试减法(失败场景,因为业务类有bug)
    @Test(description = "测试减法功能", priority = 2) 
    public void testSubtract() {
        int result = calculator.subtract(5, 3);
        Assert.assertEquals(result, 2, "减法计算错误!"); // 实际结果是 3,断言失败
        System.out.println("减法测试执行完成");
    }
}

(3)运行测试用例:IDE 直接运行

右键点击测试类 CalculatorTest → 选择「Run 'CalculatorTest'」;

或右键点击单个 @Test 方法(如 testAdd)→ 「Run 'testAdd'」(仅运行该方法)。

(4)生成html报告通过 Maven 命令运行(好像得额外配置)

打开终端,进入项目根目录;

执行命令:mvn test(会自动执行 src/test/java 下所有 TestNG 测试类);

执行结果会在终端输出,同时生成 HTML 报告(路径:target/surefire-reports/index.html)。

5、分组测试(Groups)

场景:将用例分为「冒烟测试组(smoke,核心功能)」和「回归测试组(regression,全量功能)」,上线前仅执行冒烟用例。

1.测试方法添加 groups 属性:

java 复制代码
@Test(description = "测试加法功能", groups = {"smoke", "regression"}) // 属于两个组
public void testAdd() { ... }

@Test(description = "测试减法功能", groups = {"regression"}) // 仅属于回归组
public void testSubtract() { ... }

2.在src/test/resources下创建 testng.xml 文件;配置 testng.xml,仅执行「smoke」组:

xml 复制代码
<suite name="CalculatorSuite">
    <test name="SmokeTest">
        <groups>
            <run>
                <include name="smoke"/> <!-- 包含冒烟组 -->
                <exclude name="regression"/> <!-- 排除回归组(可选) -->
            </run>
        </groups>
        <classes>
            <class name="com.testng.demo.CalculatorTest"/>
        </classes>
    </test>
</suite>
  1. 运行 XML 套件:仅 testAdd 方法会执行。

6、参数化测试(多组数据批量执行)

TestNG 支持 2 种参数化方式,按需选择:

(1)方式1:@Parameters(从 XML 读取参数,适合简单场景)

1.测试方法添加 @Parameters 注解:

java 复制代码
// 从 XML 中读取 a、b、expected 三个参数
@Test(description = "参数化测试加法(XML方式)", groups = "smoke")
@Parameters({"a", "b", "expected"})
public void testAddWithXmlParams(int a, int b, int expected) {
    int result = calculator.add(a, b);
    Assert.assertEquals(result, expected, "加法参数化测试失败");
}

2.XML 中配置参数:

xml 复制代码
<suite name="ParameterSuite">
    <test name="AddParamTest">
        <!-- 配置参数 -->
        <parameter name="a" value="2"/>
        <parameter name="b" value="3"/>
        <parameter name="expected" value="5"/>
        <classes>
            <class name="com.testng.demo.CalculatorTest"/>
        </classes>
    </test>
    <!-- 可添加多个 <test> 标签,实现多组参数 -->
    <test name="AddParamTest2">
        <parameter name="a" value="10"/>
        <parameter name="b" value="20"/>
        <parameter name="expected" value="30"/>
        <classes>
            <class name="com.testng.demo.CalculatorTest"/>
        </classes>
    </test>
</suite>

(2)方式2:@DataProvider(推荐,动态提供多组数据,适合复杂场景)

1.编写数据提供者方法(返回 Object[][],每组数据对应一行):

java 复制代码
// 数据提供者:方法名自定义,需加 @DataProvider 注解,指定 name(供测试方法引用)
@DataProvider(name = "addData")
public Object[][] provideAddData() {
    // 每组数据:{a, b, expected}
    return new Object[][]{
            {2, 3, 5},    // 正常场景
            {0, 0, 0},    // 边界场景
            {-1, 5, 4},   // 负数场景
            {100, 200, 300} // 大数场景
    };
}

2.测试方法引用数据提供者:

java 复制代码
// 参数需要一一对应
@Test(description = "参数化测试加法(DataProvider方式)", dataProvider = "addData")
public void testAddWithDataProvider(int a, int b, int expected) {
    int result = calculator.add(a, b);
    Assert.assertEquals(result, expected, "加法数据提供者测试失败");
}

3.运行测试:会自动执行 4 组数据,每组独立运行。

7、依赖测试(控制方法执行顺序)

场景:测试"下单"功能前,必须先执行"登录"功能(登录成功才会下单)。

java 复制代码
// 登录测试(依赖的前置方法)
@Test(description = "模拟登录")
public void testLogin() {
    System.out.println("执行登录操作,登录成功");
    // 实际场景中可存储登录态(如 Token)
}

// 下单测试(依赖 testLogin 方法,仅当 testLogin 成功时才执行)
@Test(description = "模拟下单", dependsOnMethods = "testLogin")
public void testPlaceOrder() {
    System.out.println("执行下单操作,下单成功");
}

// 支付测试(依赖 testPlaceOrder 方法,且依赖 testLogin 方法)
@Test(description = "模拟支付", dependsOnMethods = "testPlaceOrder")
public void testPay() {
    System.out.println("执行支付操作,支付成功");
}

执行顺序:testLogintestPlaceOrdertestPay

testLogin 失败,testPlaceOrdertestPay 会被标记为 SKIPPED(跳过)。

8、并行执行(提升测试效率)

场景:1000 条接口测试用例,单线程执行需 1 小时,并行后需 10 分钟。

通过 testng.xml 配置并行执行,核心参数:
parallel:并行级别(tests/classes/methods/instances);
methods:最常用,所有 @Test 方法并行执行;
classes:每个测试类一个线程,类内方法串行;
thread-count:并发线程数(根据机器性能调整,如 10-20)。

配置示例:

xml 复制代码
<suite name="ParallelSuite" parallel="methods" thread-count="10">
    <test name="ParallelTest">
        <classes>
            <class name="com.testng.demo.CalculatorTest"/>
            <!-- 可添加多个测试类 -->
        </classes>
    </test>
</suite>

注意:并行执行时需保证测试方法线程安全(如避免共享全局变量,数据库操作需加锁)。

9、失败重试(提高测试稳定性)

场景:网络波动导致接口测试偶尔失败,需自动重试 2 次。

实现步骤:

1.自定义重试监听器(实现 IRetryAnalyzer 接口):

java 复制代码
package com.testng.demo;

import org.testng.IRetryAnalyzer;
import org.testng.ITestResult;

// 失败重试监听器
public class RetryListener implements IRetryAnalyzer {
    // 最大重试次数
    private static final int MAX_RETRY_COUNT = 2;
    // 当前重试次数
    private int retryCount = 0;

    @Override
    public boolean retry(ITestResult result) {
        if (retryCount < MAX_RETRY_COUNT) {
            retryCount++;
            System.out.println("测试方法 " + result.getName() + " 第 " + retryCount + " 次重试");
            return true; // 允许重试
        }
        return false; // 不允许重试
    }
}

2.测试方法引用重试监听器:

java 复制代码
@Test(description = "测试减法功能", retryAnalyzer = RetryListener.class)
public void testSubtract() { ... }

3.运行测试:若方法失败,会自动重试 2 次,重试成功则标记为 PASSED

10、集成 Jenkins(持续集成)

场景:代码提交后,Jenkins 自动拉取代码、执行 TestNG 测试、生成报告并告警。

配置步骤:

1.Jenkins 安装 TestNG 插件(「系统管理」→「插件管理」→ 搜索「TestNG Plugin」安装);

2.新建 Jenkins 任务(自由风格或 Pipeline);

3.配置源码管理(Git,输入代码仓库地址);

4.配置构建步骤:

选择「Invoke top-level Maven targets」;

目标(Goals):clean test

5.配置测试报告:

构建后操作 → 选择「Publish TestNG Results」;

测试报告 XMLs:**/testng-results.xml(TestNG 自动生成的报告文件);

6.保存并构建:Jenkins 会自动执行测试,在任务页面查看测试结果和报告。

相关推荐
曾经的三心草1 小时前
JavaEE初阶-多线程2
android·java·java-ee
川石课堂软件测试1 小时前
自动化过程中验证码的解决思路
数据库·python·功能测试·测试工具·单元测试·tomcat·自动化
Boop_wu2 小时前
[Java EE] 多线程 -- 初阶(5) [线程池和定时器]
java·开发语言
十二测试录2 小时前
测试用例,常见的一些问题
功能测试·单元测试·测试用例·压力测试·可用性测试
x***J3482 小时前
测试驱动开发:从单元测试到集成测试
驱动开发·单元测试·集成测试
雨中飘荡的记忆3 小时前
Java + Groovy计费引擎详解
java·groovy
嘟嘟w3 小时前
JVM(Java 虚拟机):核心原理、内存模型与调优实践
java·开发语言·jvm
合作小小程序员小小店3 小时前
web开发,在线%药店管理%系统,基于Idea,html,css,jQuery,java,ssm,mysql。
java·前端·mysql·jdk·html·intellij-idea
ZHE|张恒3 小时前
设计模式(八)组合模式 — 以树结构统一管理对象层级
java·设计模式·组合模式