第一章、概论
一、概述
TestNG(Testing Next Generation)是专为 Java 语言设计的开源自动化测试框架,最初由 Cédric Beust 开发。其设计目标是弥补 JUnit 的局限性,提供更灵活、更强大的测试能力,尤其适用于复杂集成测试和大规模测试套件管理。
Junit 单元测试(主要是开发人员对一些方法进行测试),单元测试(类和方法)是我们测试的最小颗粒。
在测试工作中,测试框架是不可或缺的,前有Junit和Nunit框架,后有TestNG。TestNG不但吸取了Junit和Nunit框架的思想,而且创造了更强大的功能,它不但是单元测试框架,同时也是集成测试框架,也是一个优秀的自动化测试框架。TestNG突破了以前一些框架的限制,成为用途最广泛的测试框架之一。
测试是检查应用程序功能以确保其按要求运行的过程,单元测试在开发人员级别进行了描述,其中采取了足够的措施来测试每个实体(类或方法),以确保最终产品满足要求,JUnit促使开发人员了解与任何其他测试框架相比,测试的有用性,特别是单元测试的有用性,利用相当简单,实用和严格的架构。
二、IDEA配置TestNG
1、配置Maven Helper插件
2、配置Create TestNG XML插件
点击当前模块中的任意文件,右键选择
3、在pom.xml中配置TestNG依赖
创建maven工程,在pom.xml文件配置testng依赖即可。
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
三、TestNG框架特性
1、支持注解方式
支持@Test等基础注解
2、支持面向对象特性
基于Java语言开发,支持面向对象
3、支持测试集成类
调用类中的方法,必须先new一个实例对象,然后通过实例对象调用类的方法,TestNG自动化测试框架可以不需要new对象,直接运行测试方法。即不需要为每个测试类创建一个新的测试实例。
4、支持testng.xml配置文件
testng.xml文件可以配置我们想要运行的类,方法,排出我们不想运行的方法,进行灵活配置。
5、支持多个测试方法并行运行测试
并发(CONCURRENCY)与并行(PARALLELISM)
- 并发:
多个任务在单核CPU上通过时间片轮转交替执行,逻辑上“同时”运行(如同时下载文件和处理用户输入)。- 并行:
多个任务在多核CPU上物理上真正同时执行(如视频渲染时多核同时处理不同帧)
6、支持多线程测试
进程(PROCESS)
- 定义:
进程是操作系统进行资源分配和调度的基本单元,是程序的一次动态执行过程。例如,运行一个浏览器程序时,操作系统会为其创建一个进程,并分配独立的内存空间和系统资源。 - 特点:
- 独立性:每个进程拥有独立的地址空间,互不干扰。
- 资源开销大:进程的创建、切换和销毁需要较高的系统资源。
- 通信成本高:进程间需通过IPC(Inter-Process Communication)机制通信,如管道、信号量等。
线程(THREAD)
- 定义:
线程是进程内的执行单元,共享进程的资源(如内存、文件句柄),但拥有独立的程序计数器、栈空间和寄存器状态1。 - 特点:
- 轻量级:线程的创建和切换开销远小于进程。
- 资源共享:线程可直接访问进程的全局变量,但也需同步机制(如互斥锁)避免竞态条件。
- 协作高效:适用于需要频繁交互的任务,如GUI应用中的界面响应与后台计算。
四、TestNG框架命名规范最佳实践详解
1、测试套件(TEST SUITE)命名规范
1.1、模块/功能导向命名
按业务模块或系统功能划分测试套件,便于快速定位测试范围。
<suite name="LoginModuleSuite"> <!-- 登录模块套件 -->
<suite name="PaymentRegressionSuite"> <!-- 支付模块回归套件 -->
1.2、环境/类型标识
在名称中体现测试类型(冒烟、回归)或环境(预发、生产),增强可读性。
<suite name="SmokeTest_StagingEnv"> <!-- 预发环境冒烟测试 -->
<suite name="FullRegression_ProductionEnv"> <!-- 生产环境全量回归 -->
2、测试类(TEST CLASS)命名规范
2.1、类名与功能强关联
类名需明确反映被测功能,采用“功能名+Test”格式。
public class LoginPageTest {} // 登录页面测试
public class PaymentServiceTest {} // 支付服务测试
3、测试方法(TEST METHOD)命名规范
方法名可以随意命名,不一定需要以test开头,junit 的方法必须是test_开头
3.1、行为驱动命名(BDD风格)
使用“Given-When-Then”结构描述测试场景,强调预期结果:
@Test
public void userShouldBeRedirectedToDashboardAfterValidLogin() { ... } // 有效登录后应跳转至仪表盘
3.2、明确失败条件
对异常场景命名时,需说明触发条件和预期错误:
@Test
public void loginShouldFailWithInvalidCredentials() { ... } // 无效凭证应导致登录失败
3.3、避免泛型命名
反例:testCase1()
正例:customerCanCancelOrderWithin24Hours()
第二章、核心生命周期注解及执行顺序
一、概述
二、套件级控制(suite)
在测试类中定义,有几个suite运行几次
1、测试套件的定义与用途
1.1、定义
测试套件(Test Suite) 是一组逻辑相关的测试用例的集合,用于对软件中的特定功能、模块或场景进行系统化验证。其核心目的是通过结构化方式组织测试用例,提升测试效率和可维护性。例如,在测试数学工具类时,可将加法、减法等操作封装到名为
MathUtilsTestSuite
的测试套件中。
1.2、主要用途
-
结构化测试组织
将针对同一功能或模块的测试用例集中管理,例如将用户登录相关的测试(正常登录、密码错误、超时等)归入LoginTestSuite
。 -
提升维护性
当代码变更时,可快速定位并执行相关测试套件,减少回归测试的工作量。例如,修改支付模块后,仅需运行PaymentTestSuite
即可验证功能稳定性。 -
支持批量执行与过滤
在持续集成(CI)中,可针对不同环境选择特定测试套件执行(如仅运行单元测试套件或集成测试套件)。 -
复用测试逻辑
通过测试套件级别的夹具(如SetUp()
和TearDown()
),统一管理测试前置条件(如数据库连接初始化)和清理操作。
1.3、典型应用场景
- 单元测试:为每个类或函数创建独立的测试套件(如
MathUtilsTestSuite
)1。 - 回归测试:将高频执行的用例封装为回归测试套件,快速验证核心功能4。
- 模块化测试:在微服务架构中,为每个服务设计专属测试套件3。
2、案例
import org.testng.annotations.BeforeSuite; import org.testng.annotations.AfterSuite;@BeforeSuite // 整个测试套件开始前执行
@AfterSuite // 整个测试套件结束后执行
package com.testng.生命周期注解.套件级控制;
import org.testng.annotations.Test;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.AfterSuite;
/**
* before suite
* test1
* test2
* after suite
*/
public class TestSuite {
TestSuite() {
}
@BeforeSuite
void testBeforeSuite(){
System.out.println("before suite");
}
@AfterSuite
void testAfterSuite(){
System.out.println("after suite");
}
@Test
void test1(){
System.out.println("test1");
}
@Test
void test2(){
System.out.println("test2");
}
}
三、测试模块级(test)
在测试类中定义,有几个test测试集就运行几次
package com.testng.生命周期注解.测试模块级;
import org.testng.annotations.Test;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
/**
* testBeforeTest
* test1
* test2
* testAfterTest
*/
public class TestTest {
public TestTest(){}
@BeforeTest
public void testBeforeTest(){
System.out.println("testBeforeTest");
}
@AfterTest
public void testAfterTest(){
System.out.println("testAfterTest");
}
@Test
void test1(){
System.out.println("test1");
}
@Test
void test2(){
System.out.println("test2");
}
}
四、类级别控制(class)
在测试类中定义,只会运行一次
package com.testng.生命周期注解.类级别控制;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* testBeforeClass
* test1
* test2
* testAfterClass
*/
public class TestClass {
public TestClass(){}
@BeforeClass
public void testBeforeClass(){
System.out.println("testBeforeClass");
}
@AfterClass
public void testAfterClass(){
System.out.println("testAfterClass");
}
@Test
static void test1(){
System.out.println("test1");
}
@Test
void test2(){
System.out.println("test2");
}
}
五、方法级包裹(method)
在测试类中定义,有几个以@Test注解的方法就运行几次
package com.testng.生命周期注解.方法级包裹;
import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.AfterMethod;
/***
* testBeforeMethod
* test1
* testAfterMethod
* testBeforeMethod
* test2
* testAfterMethod
*/
public class TestMethod {
protected TestMethod() {
}
@BeforeMethod
public void testBeforeMethod(){
System.out.println("testBeforeMethod");
}
@AfterMethod
public void testAfterMethod(){
System.out.println("testAfterMethod");
}
@Test
void test1() {
System.out.println("test1");
}
@Test
void test2() {
System.out.println("test2");
}
}
第三章、TestNG配置文件
一、概述
TestNG的
testng.xml
文件是测试套件配置的核心文件,用于定义测试类、参数化配置、线程池设置等。
- 可以存在多个testng.xml配置文件(起不同的名称)
二、配置文件基本结构
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="自定义套件名称" parallel="methods" thread-count="5">
<parameter name="全局参数名" value="参数值"/>
<test name="测试模块名称">
<parameter name="局部参数名" value="参数值"/>
<classes>
<class name="com.example.TestClass1"/>
<class name="com.example.TestClass2"/>
</classes>
</test>
</suite>
三、<suite>
测试套件容器
一个配置xml文件中有且仅有一个suite标签
顶层容器,定义测试套件的全局配置
<suite name="RegressionSuite" parallel="methods" thread-count="5" configfailurepolicy="continue">
<parameter name="browser" value="chrome"/>
<test name="LoginTest">
<!-- 具体测试内容 -->
</test>
</suite>
- 关键属性
name
:套件唯一标识(必填),即测试报告存放的路径parallel
:并发模式(可选值:tests|classes|methods|instances
)thread-count
:并发线程数(需配合parallel
使用)configfailurepolicy
:配置失败处理策略(continue
或skip
)- 典型场景:跨模块集成测试时,通过
parallel="methods"
加速执行
四、<test>
独立测试模块
必须在suite标签中,可以有多个test标签
定义独立测试模块
<test name="PaymentTest" preserve-order="true" enabled="true">
<groups>
<run>
<include name="smoke"/>
<exclude name="broken"/>
</run>
</groups>
<classes>
<class name="com.test.PaymentServiceTest"/>
</classes>
</test>
- name:测试模块名称,即测试报告上测试集的名称
- preserve-order:控制methodmethod执行顺序
- parameters:当前测试模块专用参数
- 关键属性
preserve-order
:控制方法执行顺序(默认true
,按XML定义顺序执行)enabled
:是否启用该测试模块(默认为true
)- 典型场景:隔离执行高风险模块(如支付流程)
五、<classes>
测试类集合
必须在test标签中,可以有多个classes标签
指定具体测试类
<classes>
<class name="com.test.UserServiceTest">
<methods>
<include name="testCreate.*"/>
<exclude name="testDelete.*"/>
</methods>
</class>
<class name="com.test.OrderServiceTest"/>
</classes>
- 层级关系:必须包含在
<test>
标签内- 规则说明:若未指定
<methods>
,默认执行类中所有@Test
方法
六、<class>
单个测试类
必须在classes标签中,可以有多个class标签
指定具体要执行的测试类
<class name="com.test.TestCase1">
<methods>
<include name="testLoginSuccess"/>
<exclude name="testLoginFailure"/>
</methods>
</class>
- 关键属性
name
:类的全限定名(包路径+类名)- 典型错误:未配置
<methods>
时,类中所有@Test
方法都会执行
七、<methods>
方法过滤器
必须在class标签中,只能有一个methods标签
通过正则表达式筛选测试方法
<methods>
<include name="test.*"/>
<exclude name=".*PerformanceTest"/>
</methods>
- 匹配规则:
include
:包含符合正则表达式的方法,只能有一个方法名,可以有多个include标签exclude
:排除符合正则表达式的方法,只能有一个方法名,可以有多个exclude标签- 优先级:
exclude
的优先级高于include
八、 <packages>指定测试类包路径
在TestNG的配置文件(
testng.xml
)中,<package>
标签用于批量指定测试类所在的包路径,通过通配符匹配包内的测试类。它通常嵌套在<packages>
标签内,与<test>
标签配合使用。
<suite name="Suite">
<test name="PackageTest">
<packages>
<package name="com.example.tests.ui.*"/>
<package name="com.example.tests.api">
<exclude name=".*integration.*"/>
</package>
</packages>
</test>
</suite>
- 批量包含测试类:指定
name="com.example.tests.*"
时,会递归包含该包及子包下所有测试类- 支持正则表达式:使用
.*
匹配任意字符,例如name=".*service"
会匹配所有以service
结尾的包- 与过滤器配合:可通过
<include>
和<exclude>
子标签细化控制范围
- 当需要排除特定环境(如集成测试环境)的测试类时:须用正则表达式过滤当前指定大包全限定包名中的小包名
- 优先级规则:当同时存在
<classes>
和<package>
时,会合并两者的测试类- 路径匹配:必须使用完整包路径,不支持相对路径
- 执行顺序:默认按字母顺序执行包内的测试类
九、<groups>测试方法分组
1、<groups>
标签的核心功能
-
测试方法分组
- 通过
@Test(groups="组名")
注解标记测试方法属于特定组 - 示例:
@Test(groups = {"smoke", "regression"})
表示方法属于冒烟测试和回归测试组1
- 通过
-
动态选择执行范围
- 在XML配置中定义需要包含或排除的组
- 支持正则表达式匹配组名
2、XML配置文件语法结构
配置groups必须有classes标签指定测试类,groups标签必须在test标签下,且必须在最上方
<suite name="Suite">
<test name="Test">
<groups>
<define name="自定义组">
<include name="基础组"/>
<exclude name="排除组"/>
</define>
<run>
<include name="smoke"/>
<exclude name="broken.*"/>
</run>
</groups>
<classes>
<class name="com.example.TestClass"/>
</classes>
</test>
</suite>
3、运行配置(<RUN>
)
4、层级关系
graph TD
A[Test Suite] --> B[Test]
B --> C[Groups]
C --> D[Define]
C --> E[Run]
E --> F[Include/Exclude]
5、代码实例
public class LoginTest {
@Test(groups = {"smoke", "frontend"})
public void testValidLogin() {}
@Test(groups = {"regression", "security"})
public void testSQLInjection() {}
}
<run>
<include name="frontend"/>
<exclude name="security"/>
</run>
十、配置文件标签执行顺序
1、套件层级的顺序控制
<suite>
作为根容器
- 一个testng.xml只能包含一个
<suite>
标签 - 示例:
<suite name="主套件">
<test name="模块A测试"/>
<test name="模块B测试"/>
</suite>
<test>
标签顺序执行
- 按照XML中的声明顺序执行
- 第一个
<test>
块全部执行完成后才进入第二个 - 可通过
preserve-order="true"
强制保持顺序(默认启用)
十一、配置文件运行方式
1、Maven项目集成
pom.xml配置(需绑定Surefire插件)
可以运行多个testng配置文件,既同时运行多个测试套。
<build>
<!-- 配置testng配置文件 -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M7</version>
<configuration>
<suiteXmlFiles>
<!-- 相对与pom.xml文件的相对路径 -->
<suiteXmlFile>testsuite/testng.xml</suiteXmlFile>
<!-- 相对与pom.xml文件的绝对路径 -->
<suiteXmlFile>C:\Users\13476\Desktop\java项目\JavaTestNGTest\JavaTestNGTest\testsuite\parametersuite.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
命令行触发
mvn test
2、IDE可视化执行
右键点击XML文件 → Run ‘testng.xml’
第四章、@Test注解
一、基本功能
@Test 是 TestNG 框架中标记测试方法的核心注解,用于定义独立的测试用例。每个被注解的方法会被识别为测试执行的最小单元
二、核心属性与功能
1、分组测试
groups
:逻辑归类用例,可通过 XML 配置按组运行测试
@Test(groups = {"smoke", "regression"})
public void searchTest() { ... }
2、动态开关用例
enabled
:临时禁用测试,用于跳过未完成或已知缺陷的用例
@Test(enabled = false)
public void deprecatedTest() { ... }
3、优先级
priority:测试优先级,功能:控制测试方法的执行顺序,数值越小优先级越高。
@Test(priority = 1)
public void testLogin() {
System.out.println("登录测试");
}
@Test(priority = 2)
public void testUserAction() {
System.out.println("用户操作测试");
}
4、方法依赖
dependsOnMethods:功能:当前测试方法仅在所依赖的其他方法成功执行后才会运行。
@Test
public void testLogin() { /* ... */ }
@Test(dependsOnMethods = "testLogin")
public void testDashboardAccess() {
System.out.println("依赖登录成功后执行");
}
- 若
testLogin
失败,testDashboardAccess
会被标记为SKIP
。
第五章、TestNG参数化
必须使用testng.xml文件来运行测试类,不能在测试类中运行
一、 <parameter>静态参数化
1、配置参数优先级
在testng.xml
中参数作用域遵循:
优先级顺序:方法级 > 类级 > 测试级 > 套件级
- 只能在test和suite标签下添加<parameter>标签,且test中添加的参数化优先级比suite中的优先级高。
- 一个parameter标签只能传一个参数
<suite name="Suite">
<parameter name="env" value="prod"/> <!-- 套件级参数 -->
<test name="Test">
<parameter name="env" value="dev"/> <!-- 测试级覆盖 -->
<classes>
<class name="TestCases"/>
</classes>
</test>
</suite>
2、测试类接收参数
public class TestCases {
@Test
@Parameters({"username", "password"})
public void loginTest(String user, String pwd) {
System.out.println("用户:" + user + " 密码:" + pwd);
}
}
二、@DataProvider动态参数化
@DataProvider 标记一种方法来提供测试方法的数据。 注释方法必须返回一个Object[][]二维数组,其中每个Object[]可以被分配给测试方法的参数列表。要从该DataProvider接收数据的@Test方法需要使用与此注释名称相等的dataProvider名称
1、基础数据驱动
@DataProvider(name = "searchData")
public Object[][] provideData() {
return new Object[][] {
{"Java", 10},
{"Python", 20},
{"TestNG", 30}
};
}
@Test(dataProvider = "searchData")
public void searchTest(String keyword, int count) {
// 执行搜索逻辑
}
2、类型自动转换特性
TestNG支持自动类型转换:
@DataProvider
public Object[][] numberData() {
return new Object[][] { {"100"}, {200} };
}
@Test(dataProvider = "numberData")
public void testNumbers(int num) { // 字符串"100"自动转为int
Assert.assertTrue(num > 0);
}
第六章、测试报告
一、使用默认测试报告模板
1、报告路径和名称说明
二、使用reportng插件生成报告
1、在pom.xml文件中配置依赖
<dependency>
<groupId>org.uncommons</groupId>
<artifactId>reportng</artifactId>
<version>1.1.4</version>
<scope>test</scope>
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <groupId>org.testng</groupId>-->
<!-- <artifactId>testng</artifactId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>4.2.0</version>
</dependency>
2、去勾选默认报告模板
把之前默认报告的选项去勾选掉
3、在testng配置文件中新增<listeners>
<listeners>
<listener class-name="org.uncommons.reportng.HTMLReporter"/>
<listener class-name="org.uncommons.reportng.JUnitXMLReporter"/>
</listeners>
三、TestNG 测试报告的作用
- 第一点、测试报告是测试执行中重要组成部分,因为它可以帮用户理解测试执行的结果,失败还是成功
- 第二点、可以分析和记录失败的原因
- 第三点、TestNG 生成两种不同的格式输出:HTML XML 两种格式进行报告输出
- 第四点、常用的报告生成类有哪一些org.testng.ITestlistener 可以监听测试开始 结束 失败 通过等org.testng.IReporter
- 第五点、可以通过一些依赖包或者插件美化测试报告
第七章、断言
TestNG作为Java测试框架,通过丰富的断言机制实现精准的测试验证,主要分为基础断言、高级断言和软断言三类。
一、硬断言
org.testng.Assert:封装了一些列断言的静态方法
如果断言失败,后面还有其他的代码,也不会继续执行下去,该测试类中的其他测试方法也不会执行
1、Assert.assertTrue()
验证条件是否为真,常用于布尔表达式验证。
Assert.assertTrue(5 > 3, "条件不满足时显示此消息");
2、Assert.assertFalse()
验证条件是否为假,与
assertTrue
逻辑相反
Assert.assertFalse("text".isEmpty(), "字符串非空时失败");
3、Assert.assertEquals()
验证实际值与预期值是否相等,支持多种数据类型(基本类型、对象、集合等)
Assert.assertEquals("Hello", actualString, "字符串不匹配");
4、Assert.assertSame()
验证两个对象是否为同一实例
Assert.assertSame(obj1, obj2, "对象引用不同");
5、Assert.assertNotSame()
验证对象引用不同
6、Assert.assertNull()
验证对象为
null
7、Assert.assertNotNull()
验证对象非
null
二、软断言
通过
SoftAssert
类实现,允许在单次测试中执行多个断言,最后统一报告失败信息。
使用步骤:
- 创建
SoftAssert
实例 - 执行多个断言
- 调用
assertAll()
汇总结果
SoftAssert softAssert = new SoftAssert();
softAssert.assertEquals(a, b, "数值不等");
softAssert.assertTrue(list.isEmpty(), "列表非空");
softAssert.assertAll(); // 必须调用以触发验证
作用:避免因单个断言失败导致后续验证中断,适合需要全面检查多个条件的场景(如表单字段验证)。