TestNG自动化测试框架基础篇

第一章、概论

 一、概述

        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、主要用途
  1. 结构化测试组织
    将针对同一功能或模块的测试用例集中管理,例如将用户登录相关的测试(正常登录、密码错误、超时等)归入 LoginTestSuite

  2. 提升维护性
    当代码变更时,可快速定位并执行相关测试套件,减少回归测试的工作量。例如,修改支付模块后,仅需运行 PaymentTestSuite 即可验证功能稳定性。

  3. 支持批量执行与过滤
    在持续集成(CI)中,可针对不同环境选择特定测试套件执行(如仅运行单元测试套件或集成测试套件)。

  4. 复用测试逻辑
    通过测试套件级别的夹具(如 SetUp()TearDown()),统一管理测试前置条件(如数据库连接初始化)和清理操作。

1.3、典型应用场景
  • 单元测试:为每个类或函数创建独立的测试套件(如 MathUtilsTestSuite1
  • 回归测试:将高频执行的用例封装为回归测试套件,快速验证核心功能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文件是测试套件配置的核心文件,用于定义测试类、参数化配置、线程池设置等。

  1. 可以存在多个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:配置失败处理策略(continueskip
  • 典型场景:跨模块集成测试时,通过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>标签的核心功能

  1. 测试方法分组

    • 通过@Test(groups="组名")注解标记测试方法属于特定组
    • 示例:@Test(groups = {"smoke", "regression"})表示方法属于冒烟测试和回归测试组1
  2. 动态选择执行范围

    • 在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类实现,允许在单次测试中执行多个断言,最后统一报告失败信息。

使用步骤

  1. 创建SoftAssert实例
  2. 执行多个断言
  3. 调用assertAll()汇总结果
SoftAssert softAssert = new SoftAssert();
softAssert.assertEquals(a, b, "数值不等");
softAssert.assertTrue(list.isEmpty(), "列表非空");
softAssert.assertAll(); // 必须调用以触发验证

作用:避免因单个断言失败导致后续验证中断,适合需要全面检查多个条件的场景(如表单字段验证)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值