Java-单元测试框架:TestNG详解(对比JUnit)
Java中常用测试框架为JUnit和TestNG,两个框架都能提供断言、执行、报告等能力。
- 单元测试:对软件中的最小可测试单元进行测试,比如方法、类等
- JUnit:适合传统的、独立的、无依赖的单元测试。
- TestNG:更适合测试场景,尤其是需要数据驱动、测试依赖、分组、并发等复杂功能的自动化测试项目。
1、TestNG 基本结构与执行顺序
执行顺序:@BeforeSuite -> @BeforeTest -> @BeforeClass -> @BeforeMethod -> @Test -> @AfterMethod -> @AfterClass -> @AfterTest -> @AfterSuite
import org.testng.annotations.*; public class TestNGStructureDemo { @BeforeSuite public void beforeSuite() { System.out.println("1. BeforeSuite - 整个套件前执行一次"); } @BeforeTest public void beforeTest() { System.out.println("2. BeforeTest - 整个测试前执行"); } @BeforeClass public void beforeClass() { System.out.println("3. BeforeClass - 当前类前执行一次"); } @BeforeMethod public void beforeMethod() { System.out.println("4. BeforeMethod - 每个测试方法前执行"); } @Test // 标记方法为测试方法,标记类为测试类(测试类下的所有方法都是测试方法) public void testA() { System.out.println("5. Test - testA"); } }
2、 数据驱动测试(@DataProvider - TestNG 核心优势)
import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; public class DataProviderDemo { // 1. 定义数据提供者,返回 Object[][] @DataProvider(name = "userData") public Object[][] provideUserData() { return new Object[][] { {"admin", "password123", true}, {"test", "wrong", false}, {"user", "pass", false} }; } // 2. 测试方法使用 dataProvider 属性引用数据 @Test(dataProvider = "userData") public void testLogin(String username, String password, boolean expectedResult) { // 模拟登录验证逻辑 boolean actualResult = loginService.login(username, password); assertEquals(actualResult, expectedResult); } }
注意:如果@DataProvider和@Test在不同的类,需要通过dataProviderClass属性指定@DataProvider所在的类
-
@Test(dataProvider = "xx", dataProviderClass = xx.class)
4、测试依赖(dependsOnMethods)
public class DependencyDemo { @Test public void testLogin() { System.out.println("登录成功"); // 假设登录成功,设置一个标志 } @Test(dependsOnMethods = "testLogin") public void testQueryOrder() { System.out.println("查询订单(依赖登录)"); // 依赖testLogin,只有 testLogin 成功,此方法才会执行 } @Test(dependsOnMethods = {"testLogin", "testQueryOrder"}) public void testLogout() { System.out.println("退出登录(依赖前两个)"); } }
5、分组测试(groups)
执行顺序:@BeforeSuite -> @BeforeTest -> @BeforeClass -> @BeforeGroups -> @Test
public class GroupDemo { @Test(groups = "smoke") public void testLogin() { System.out.println("冒烟测试:登录"); } @Test(groups = "regression") public void testUserSearch() { System.out.println("回归测试:用户搜索"); } @Test(groups = {"smoke", "regression"}) public void testAddToCart() { System.out.println("同时属于冒烟和回归:加入购物车"); } @BeforeGroups(groups = "regression") // @BeforeGroups() 会在 regression组(groups = "regression") 第一个测试方法执行前自动运行 // @BeforeGroups() 只会执行一次 public void beforeRegression() { System.out.println("执行回归测试前的初始化工作..."); } }
6、常用的断言
断言是测试的核心,用于验证实际结果是否与预期一致。TestNG 提供了丰富的断言方法,都在 org.testng.Assert 类中。
- 带消息的断言(建议使用):Assert.assertEquals(actualName, expectedName, "用户名验证失败,期望值不匹配");
- 软断言:org.testng.asserts.SoftAssert类,断言失败时,后续代码会继续执行,等待所有断言都执行完,再汇总报告失败。
| 断言方法 | 作用 | 示例 |
|---|---|---|
assertEquals(actual, expected) |
判断两个值是否相等(调用 equals() 方法) |
Assert.assertEquals(actualSum, 100); |
assertTrue(condition) |
判断条件是否为 true | Assert.assertTrue(isLoginSuccess); |
assertNull(object) |
判断对象是否为 null | Assert.assertNull(user); |
assertSame(actual, expected) |
判断两个引用是否指向同一个对象(==) |
Assert.assertSame(obj1, obj2); |
fail() |
直接让测试失败,常用于标记“不该执行到的代码” | Assert.fail("测试不应走到这里"); |
7、testng.xml 配置文件
testng.xml 是 TestNG 的核心配置文件,通过它可以灵活组织和执行测试,而无需修改代码。
| 属性 | 作用 | 示例值 |
|---|---|---|
name |
套件/测试的名称 | "测试套件" |
parallel |
并发执行级别 | "methods"(方法级)、"classes"、"tests" |
thread-count |
并发线程数(配合 parallel 使用) |
//使用5个线程并发执行 |
verbose |
日志详细程度(0-10,越高越详细) | "2" |
preserve-order |
是否保持测试方法在类中定义的顺序执行 | "true" / "false" |
group-by-instances |
是否按实例分组 | "true" |
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="测试套件" parallel="methods" thread-count="5" verbose="2"> <!-- 1. 定义全局参数 --> <parameter name="browser" value="chrome" /> <parameter name="env" value="test" /> <!-- 2. 监听器配置(可选项,用于日志、报告等) --> <listeners> <listener class-name="org.testng.reporters.XMLReporter" /> </listeners> <!-- 3. 测试标签,可以包含多个测试 --> <test name="接口测试"> <!-- 定义该测试范围内的参数 --> <parameter name="baseUrl" value="https://api-test.example.com" /> <!-- 定义哪些包/类/方法要执行 --> <packages> <package name="com.example.api.tests" /> </packages> </test> <test name="数据库验证测试"> <parameter name="dbUrl" value="jdbc:mysql://test-db:3306" /> <!-- 指定具体的测试类 --> <classes> <class name="com.example.db.UserDaoTest" /> <class name="com.example.db.OrderDaoTest"> <!-- 只执行类中特定方法,没有任何<include>,则默认执行所有,可以使用<exclude>来跳过特定方法 --> <methods> <include name="testInsertOrder" /> <include name="testQueryOrder" /> <!-- 这里的 exclude没用,因为 testDeleteOrder 本来就没被 include,默认不会被执行 --> <exclude name="testDeleteOrder" /> </methods> </class> </classes> </test> <!-- 按分组执行 --> <test name="冒烟测试"> <groups> <run> <include name="smoke" /> <include name="login" /> <exclude name="broken" /> <!--有必要,一个方法可能同时属于 smoke 和 broken 两个组 --> </run> </groups> <!-- 必须包含<pakages>或者<classes>,指定groups来自于哪个包或者类 --> <packages> <package name="com.example.*" /> </packages> </test> </suite>
8、在代码中接收 testng.xml 的参数:
import org.testng.annotations.Parameters; import org.testng.annotations.Test; public class ParameterizedTest { @Test @Parameters({"browser", "env"}) public void testWithParameters(String browser, String env) { System.out.println("当前浏览器:" + browser); System.out.println("当前环境:" + env); // 根据参数执行不同逻辑 } }
运行方式
| 命令 | 作用 | 典型场景 |
|---|---|---|
mvn test |
默认会执行符合命名规则的测试类中的 1、默认命名规则(如 |
本地开发验证、CI 全量回归测试 |
mvn test -Dtest=TestClassName |
执行指定的测试类(支持通配符) | 只运行某个模块的测试,或调试单个类 |
mvn test -Dgroups=smoke |
执行指定分组的测试方法(按 groups 属性过滤) |
只运行冒烟测试(groups = "smoke") |
|
或IDE中运行testng.xml文件 |
执行指定的 --执行testng.xml中的测试方法 |
执行回归测试套件、多环境测试 |
mvn clean test |
先清理 target 目录,再执行测试 |
确保完全重新编译和运行,避免缓存影响 |
Maven 执行测试依赖 maven-surefire-plugin 插件;在 pom.xml 中可以配置该插件,以指定 testng.xml 文件路径、测试报告格式等。
- 在
maven-surefire-plugin插件中配置testng.xml文件路径:再执行mvn test,会自动加载项目根目录下的testng.xml文件执行测试。
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.0.0-M7</version> <configuration> <suiteXmlFiles> <suiteXmlFile>testng.xml</suiteXmlFile> </suiteXmlFiles> </configuration> </plugin> </plugins> </build>
本文来自博客园,作者:Fēngwèi,转载请注明原文链接:https://www.cnblogs.com/fengwei-blogs/p/22516747

浙公网安备 33010602011771号