TestNG入门(二):数据驱动与分组测试策略
TestNG入门(二):数据驱动与分组测试策略
1. 数据驱动测试概述
数据驱动测试(Data-Driven Testing)是自动化测试的核心理念之一。它的核心思想是将测试数据与测试逻辑分离,使得同一套测试代码可以验证多组不同的测试数据。
1.1 为什么需要数据驱动?
- 提高测试覆盖率:一个测试方法可以验证多组数据
- 减少代码重复:避免为相似场景编写多个测试方法
- 便于维护:测试数据变更时无需修改测试代码
- 支持外部数据源:可以从数据库、Excel、CSV等外部文件读取数据
2. 项目实战:用户登录系统测试
在这个项目中,我们将模拟一个用户登录系统,学习如何通过数据驱动的方式测试不同的登录场景。
2.1 被测业务类:LoginService
package org.example.proj2;
public class LoginService {
// 模拟登录逻辑
public boolean login(String username, String password) {
if("admin".equals(username) && "123456".equals(password)) {
return true;
}
return false;
}
}
2.2 数据库工具类:DBUtils
为了演示真实场景,我们创建了一个数据库工具类来模拟从数据库读取测试数据:
package org.example.proj2.utils;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import java.sql.SQLException;
import java.util.List;
public class DBUtils {
public static Object[][] getLoginData() {
try {
// 1. 一行代码查询所有数据
// Hutool 会自动读取 db.setting 并连接数据库
// findAll("表名") 返回的是 List<Entity>,Entity 本质上是一个 Map
List<Entity> entityList = Db.use().findAll("login_data");
// 2. 将 List<Entity> 转换为 TestNG 需要的 Object[][]
Object[][] data = new Object[entityList.size()][3];
for (int i = 0; i < entityList.size(); i++) {
Entity entity = entityList.get(i);
data[i][0] = entity.getStr("username");
data[i][1] = entity.getStr("password");
// 数据库里的 1/0 自动转 boolean
data[i][2] = entity.getBool("expected_result");
}
return data;
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("数据库读取失败");
}
}
}
3. 参数化测试详解
TestNG提供了两种主要的参数化方式:@Parameters和@DataProvider。
3.1 @Parameters:静态参数注入
@Parameters用于从testng.xml文件中注入静态配置参数:
// --- 1.参数注入 ---
// 从testng.xml中获取配置
// Parameters 参数化的核心 从xml中读取 比如将dbUrl改为测试环境地址, 就能直接运行
@Parameters({"testEnv"}) // 传入不同的值, 就可以在不同的环境中测试!
@BeforeClass(alwaysRun = true) // 保证在分组情况下也能运行
public void setUp(String env) throws Exception {
loginService = new LoginService();
System.out.println("【初始化】当前环境是: " + env);
}
对应的testng.xml配置:
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" >
<suite name="电商项目测试套件">
<!-- 全局参数定义:这里的值会被注入到 @Parameters 注解中 -->
<parameter name="testEnv" value="http://testEnv.com" />
<parameter name="prodEnv" value="http://prodEnv.com" />
<test name="登录模块测试">
<!-- 分组控制(打标签):尝试取消注释下面的代码块来看看效果 -->
<groups>
<run>
<include name="smoke"/>
<include name="regression"/>
</run>
</groups>
<classes>
<!-- 指定要运行的测试类 -->
<class name="proj2.testLoginService" />
</classes>
</test>
</suite>
3.2 @DataProvider:动态数据驱动
@DataProvider是TestNG数据驱动测试的核心,它可以从各种数据源提供测试数据:
// --- 2.绑定数据 ---
// 数据驱动层 : 将测试数据和测试代码分离 可以从数据库/excel中读取数据 参数name只是一个标识
@DataProvider(name = "testData")
public Object[][] createData() {
System.out.println("【数据驱动】正在从 MySQL 数据库加载测试数据...");
// 调用工具类获取数据
return DBUtils.getLoginData();
}
3.3 绑定DataProvider的测试方法
// --- 3.绑定数据的测试方法 ---
// 这里的dataProvider要和上面保持一致 在xml中配置分组
// groups : 分给测试打标签, 灵活选择要执行的分组(smoke, regression, p0...)
@Test(dataProvider = "testData", groups = {"regression"})
public void testLogin(String username, String password, boolean expectedResult) {
System.out.println(
"【回归测试】正在测试登录功能,username: " + username + ", password: " + password
);
boolean result = loginService.login(username, password);
Assert.assertEquals(result, expectedResult);
}
4. 测试分组策略
TestNG的分组功能允许我们为测试方法打标签,然后根据需要选择性地执行特定的测试组。
4.1 定义测试分组
// --- 4.冒烟测试 ---
@Test(groups = {"smoke"})
public void testHomepage() {
System.out.println("【冒烟测试】正在冒烟测试登录功能");
}
4.2 分组的作用
- 冒烟测试(Smoke Test):验证系统的核心功能是否正常工作
- 回归测试(Regression Test):验证现有功能没有被新代码破坏
- P0测试:最关键的测试用例
- 集成测试:验证模块间的集成
4.3 分组执行控制
通过testng.xml可以灵活控制执行哪些分组:
<groups>
<run>
<include name="smoke"/> <!-- 只执行冒烟测试 -->
<exclude name="regression"/> <!-- 排除回归测试 -->
</run>
</groups>
5. DataProvider高级用法
5.1 内联DataProvider数据
除了从数据库读取,DataProvider也可以直接返回内联数据:
@DataProvider(name = "loginTestData")
public Object[][] provideLoginData() {
return new Object[][] {
{"admin", "123456", true}, // 正确用户名密码
{"user", "wrongpass", false}, // 错误密码
{null, null, false}, // 空用户名密码
{"admin", null, false}, // 空密码
{null, "123456", false} // 空用户名
};
}
5.2 多参数DataProvider
DataProvider可以返回任意数量和类型的参数:
@DataProvider(name = "userProfileData")
public Object[][] provideUserProfileData() {
return new Object[][] {
{"张三", 25, "男", "北京市", true},
{"李四", 30, "女", "上海市", true},
{"王五", 17, "男", "广州市", false}, // 未成年
{"", 22, "女", "深圳市", false} // 空姓名
};
}
@Test(dataProvider = "userProfileData")
public void testUserProfile(String name, int age, String gender, String city, boolean expectedValid) {
// 测试逻辑
}
6. 完整测试类示例
package proj2;
import org.example.proj2.LoginService;
import org.example.proj2.utils.DBUtils;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
/**
* 参数化测试核心注解:
* @Parameters() : 从testng.xml中获取配置, 适用于"动态化配置", 比如prod和test环境的切换
* @DataProvider() : 一般是从外部数据源获取, 比如从数据库/excel中读取数据, 返回Object[][]
* 理解数据驱动测试, 参数化测试
*/
public class testLoginService {
private LoginService loginService;
// --- 1.参数注入 ---
// 从testng.xml中获取配置
// Parameters 参数化的核心 从xml中读取 比如将dbUrl改为测试环境地址, 就能直接运行
@Parameters({"testEnv"}) // 传入不同的值, 就可以在不同的环境中测试!
@BeforeClass(alwaysRun = true) // 保证在分组情况下也能运行
public void setUp(String env) throws Exception {
loginService = new LoginService();
System.out.println("【初始化】当前环境是: " + env);
}
// --- 2.绑定数据 ---
// 数据驱动层 : 将测试数据和测试代码分离 可以从数据库/excel中读取数据 参数name只是一个标识
@DataProvider(name = "testData")
public Object[][] createData() {
System.out.println("【数据驱动】正在从 MySQL 数据库加载测试数据...");
// 调用工具类获取数据
return DBUtils.getLoginData();
}
// --- 3.绑定数据的测试方法 ---
// 这里的dataProvider要和上面保持一致 在xml中配置分组
// groups : 分给测试打标签, 灵活选择要执行的分组(smoke, regression, p0...)
@Test(dataProvider = "testData", groups = {"regression"})
public void testLogin(String username, String password, boolean expectedResult) {
System.out.println(
"【回归测试】正在测试登录功能,username: " + username + ", password: " + password
);
boolean result = loginService.login(username, password);
Assert.assertEquals(result, expectedResult);
}
// --- 4.冒烟测试 ---
@Test(groups = {"smoke"})
public void testHomepage() {
System.out.println("【冒烟测试】正在冒烟测试登录功能");
}
}
7. 核心知识点总结
7.1 testng.xml配置
- 套件(Suite):最高级别的容器,可以包含多个测试
- 测试(Test):包含一个或多个测试类
- 类(Class):具体的测试类
- 参数(Parameter):全局配置参数
7.2 @Parameters vs @DataProvider
| 特性 | @Parameters | @DataProvider |
|---|---|---|
| 数据来源 | testng.xml文件 | Java方法返回 |
| 数据类型 | 字符串 | 任意类型 |
| 使用场景 | 环境配置、全局设置 | 测试数据、业务数据 |
| 灵活性 | 较低,静态配置 | 很高,动态生成 |
7.3 分组策略优势
- 灵活执行:可以选择只运行特定分组的测试
- 分类管理:将测试用例按照重要性和类型分类
- CI/CD集成:在不同阶段运行不同的测试组
8. 最佳实践
-
DataProvider命名:
- 使用有意义的DataProvider名称
- 避免使用默认名称,便于维护
-
数据源选择:
- 简单数据:直接在代码中定义
- 复杂数据:从外部文件(Excel、CSV、JSON)读取
- 动态数据:从数据库实时获取
-
分组策略:
- 遵循业界标准命名(smoke、regression、integration)
- 避免过度细分,保持分组简洁明了
-
参数化配置:
- 将环境相关的配置放入testng.xml
- 将测试数据放入DataProvider
9. 下一步学习
掌握了数据驱动和分组测试后,下一步我们将学习:
- 测试依赖管理
- 软断言与硬断言
- 并发测试与性能模拟
- 超时控制机制
这些高级特性将让你能够处理更复杂的测试场景。
下一篇文章我们将深入探讨TestNG的依赖管理和并发测试,敬请期待!
#测试开发学习路线##简历中的项目经历要怎么写#

查看8道真题和解析