文章目录
- 一、简介
- 二、使用
-
- 1、环境
- [2、TestNG 生命周期](#2、TestNG 生命周期)
- 3、核心注解全解析
- 4、简单使用入门
-
- (1)编写被测试类(业务逻辑)
- [(2)编写 TestNG 测试类](#(2)编写 TestNG 测试类)
- [(3)运行测试用例:IDE 直接运行](#(3)运行测试用例:IDE 直接运行)
- [(4)生成html报告通过 Maven 命令运行(好像得额外配置)](#(4)生成html报告通过 Maven 命令运行(好像得额外配置))
- 5、分组测试(Groups)
- 6、参数化测试(多组数据批量执行)
-
- [(1)方式1:`@Parameters`(从 XML 读取参数,适合简单场景)](#(1)方式1:
@Parameters(从 XML 读取参数,适合简单场景)) - (2)方式2:`@DataProvider`(推荐,动态提供多组数据,适合复杂场景)
- 7、依赖测试(控制方法执行顺序)
- 8、并行执行(提升测试效率)
- 9、失败重试(提高测试稳定性)
- [10、集成 Jenkins(持续集成)](#10、集成 Jenkins(持续集成))
- [(1)方式1:`@Parameters`(从 XML 读取参数,适合简单场景)](#(1)方式1:
一、简介
官方文档: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>
- 运行 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("执行支付操作,支付成功");
}
执行顺序:testLogin → testPlaceOrder → testPay;
若 testLogin 失败,testPlaceOrder 和 testPay 会被标记为 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 会自动执行测试,在任务页面查看测试结果和报告。