【TestNG自动化测试框架详解】
TestNG自动化测试框架详解
- TestNG
- 一、概述与使用
- 1.1 配置环境
- 1.2 测试方法
- 1.3 使用xml文件
- 二、测试方法常用注解
- 2.1 配置类注解
- 2.2 非配置类注解
- 2.2.1 @Parameters
- 2.2.2 @DataProvider
- 2.2.2.1 实例
- 2.2.3 @Test
- 2.2.3.1多线程测试
- 2.2.4 @Factory
- 2.2.4.1 动态生成测试用例
- 2.2.4.2 结合参数化测试
- 2.2.4.3 结合数据驱动测试
- 2.2.5 @Listener
- 2.2.5.1 实例
- 三、依赖测试
- 四、忽略测试
- 五、超时测试
- 六、异常测试
- 七、分组测试
- 七、失败重试机制
- 7.1 IRetryAnalyzer接口
- 7.2 测试方法引入失败重试
- 7.2.1 通过注解的方式
- 7.2.2 通过实现接口 + 监听器的方式
TestNG
一、概述与使用
TestNG是一款设计测试用例执行流程的测试框架。
1.1 配置环境
- 添加依赖
<dependency><groupId>org.testng</groupId><artifactId>testng</artifactId><version>6.14.3</version>
</dependency>
- 安装插件

1.2 测试方法
//导入的两个包均为testng的
import org.testng.Assert;
import org.testng.annotations.Test;public class Tester {@Testpublic void test() {//自定义add方法用来计算两个参数的和int res = Calculator.add(3, 4);int expected = 7;//断言,如果参数的两个值一样,断言就通过,否则抛出异常Assert.assertEquals(res, expected);}
}
运行结果成功示例:

运行结果失败示例(将expected值修改为5):

1.3 使用xml文件
testng.xml 文件用来设计测试用例的执行流程, 与pom.xml 同级。
- 在对应的项目右键,选择如下:


- 生成的文件如下图:

- xml 配置文件解析
<suite>:套件就是将所有的测试类整理在一块,形成一套测试用例
<parameter> :参数,可以给测试类或测试方法传递参数</parameter>
<test>:测试集就是测试类的集合,一般把项目的某一个模块设计成一个测试集
<parallel>:指定测试集下的测试类或测试方法执行时是否采用多线程方式执行</parallel>
<groups>:指定测试集下的测试类或测试方法执行的顺序</groups>
<packages>:测试集下的所有测试类所在的包</packages>
<classes>:测试集下的所有测试类
<class>:具体测试类,name 属性指定测试类的路径
<methods>:测试类下具体的测试方法,如果不写此标签则默认包含测试类下的所有方法
以后需要执行哪些测试方法,在xml文件中编写对应的标签即可。
- 运行xml配置文件
运行 testng.xml 文件其实运行的是套件中定义的所有测试集下的所有测试类中的指定的测试方法。
xml文件右键选择Run,结果如下:

二、测试方法常用注解
2.1 配置类注解
TestNG相关注解注解 描述@BeforeSuite 在该套件的所有测试都运行在注释的方法之前,仅运行一次@AfterSuite 在该套件的所有测试都运行在注释方法之后,仅运行一次@BeforeClass 在调用当前类的第一个测试方法之前运行,注释方法仅运行一次@AfterClass 在调用当前类的第一个测试方法之后运行,注释方法仅运行一次@BeforeTest 注释的方法将在属于test标签内的类的所有测试方法运行之前运行@AfterTest 注释的方法将在属于test标签内的类的所有测试方法运行之后运行@BeforeGroups 配置方法将在之前运行组列表。 此方法保证在调用属于这些组中的任何一个的第一个测试方法之前不久运行@AfterGroups 此配置方法将在之后运行组列表。该方法保证在调用属于任何这些组的最后一个测试方法之后不久运行@BeforeMethod 注释方法将在每个测试方法之前运行@AfterMethod 注释方法将在每个测试方法之后运行@BeforeSuite -> @BeforeTest -> @BeforeGroups -> @BeforeClass -> @BeforeMethod-> 测试方法 ->@AfterMethod -> @AfterClass -> @AfterGroups -> @AfterTest -> @AfterSuite
使用上述所有注解的方法执行顺序:
BeforeSuite
BeforeTest
BeforeClass
{ BeforeMethodTestAfterMethod }
AfterClass
AfterTest
AfterSuite
注意:
-
上述
{}内的注解表示有几个@Test,这些注解标记的方法就要执行多少次 -
除了
@BeforeSuite、@BeforeTest、@AfterTest、@AfterSuite可以对不同的测试类生效外,其他注解的作用范围只在本类中生效。所以,如果想要在别的类中共用某些方法,可以将这些方法声明在上述四个注解中 -
图示如下:

2.2 非配置类注解
@Parameters 描述如何将参数传递给@Test方法@DataProvider 标记一种方法来提供测试方法的数据。 注释方法必须返回一个Object [] [],其中每个Object []可以被分配给测试方法的参数列表。 要从该DataProvider接收数据的@Test方法需要使用与此注释名称相等的dataProvider名称@Factory 将一个方法标记为工厂,返回TestNG将被用作测试类的对象。 该方法必须返回Object []@Listeners 定义测试类上的侦听器@Test 将类或方法标记为测试的一部分,此标记若放在类上,则该类所有公共方法都将被作为测试方法
2.2.1 @Parameters
-
先在
testng.xml文件中定义参数标签
-
对应的测试方法使用注解

2.2.2 @DataProvider
使用此注解的方法用来提供多组测试数据,返回值是二维数组。
使用示例:
@DataProvider
public Object[][] dataResult() {return new Object[][]{{"火星哥", 22, "男"},{"霉霉", 23, "女"}};
}@Test(dataProvider = "dataResult") //值为方法名
public void test(String name, int age, String sex) {System.out.println(name + age + sex);
}/*** @DataProvider(name = "myName"),使用时不再使用方法名,而使用指定的myName名称*/
运行结果:

注意:代码中写测试用例效率较低,一般都是读取excel中的测试用例作为返回值。
2.2.2.1 实例
- 实例一
public class demo7 {// 参数化测试2@Test(dataProvider = "data")public void test01(String name, int age) {System.out.println("name:" + name + "; age:" + age);}/*** 此方法准备测试数据** @return 要被测试的测试数据*/@DataProvider(name = "data")public Object[][] paramData(){Object[][] obj = new Object[][]{{"张三",18},{"李四",24},{"王五",26},};return obj;}}
- 实例二
public class demo8 {/*有时候我们可能需要多个测试方法传递不用的参数此方式我们也可以在执行其中某一个测试方法的时候,传递不同的参数*/@Test(dataProvider = "data")public void test01(String name, int age) {System.out.println("name:" + name + "; age:" + age);}/*** 此方法准备测试数据** @return 要被测试的测试数据*/@DataProvider(name = "data")public Object[][] paramData() {Object[][] obj = new Object[][]{{"张三", 18},{"李四", 24},{"王五", 26},};return obj;}@Test(dataProvider = "mathodData")public void test2(String name, int age) {System.out.println("test2方法 name:" + name + ";age" + age);}@Test(dataProvider = "mathodData")public void test3(String name, int age) {System.out.println("test3方法 name:" + name + ";age" + age);}/*** 此处注意不要import错包** @param method 参数* @return 返回*/@DataProvider(name = "mathodData")public Object[][] metherData(Method method) {Object[][] result = null;if (method.getName().equals("test2")) {result = new Object[][]{{"张三", 28},{"李四", 34}};} else if (method.getName().equals("test3")) {result = new Object[][]{{"王五", 36},{"赵六", 56}};}return result;}
}
- 实例三
package com.selenium.testcase.TestDemo;import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;import static org.testng.Assert.assertTrue;public class demo20 {@BeforeClasspublic void setup() {DataProviderClass.setParameters("param1", "param2");}/*** 指定测试方法使用的数据提供者、类和参数,并依赖于另一个测试方法,并指定测试方法的优先级和描述**/@Test(dataProvider = "dataProvider", // 指定数据提供者的名称dataProviderClass = DataProviderClass.class, // 测试方法使用的数据提供者的类description = "测试描述", // 测试方法的描述信息priority = 1 // 测试方法的优先级)public void test4(String value1, String value2) {System.out.println("Value1: " + value1 + ", Value2: " + value2);assertTrue(true); // 测试逻辑:断言条件为 true}
}
package com.selenium.testcase.TestDemo;import org.testng.annotations.DataProvider;public class DataProviderClass {// 通过构造函数或字段传递参数private static String param1;private static String param2;// 添加无参构造函数public DataProviderClass() {// 可以设置默认值或者留空}// 提供静态方法来设置参数public static void setParameters(String p1, String p2) {param1 = p1;param2 = p2;}/*** @DataProvider 注解标记一个方法为数据提供者。* 数据提供者方法返回一个二维数组 Object[][] ,每一行代表一组测试数据。* 参数 param1 和 param2 来自 dataProviderParameters 。* @return*/@DataProvider(name = "dataProvider")public Object[][] dataProviderMethod() {return new Object[][] {{ (param1 != null ? param1 : "default") + "_value1", (param2 != null ? param2 : "default") + "_value1" },{ (param1 != null ? param1 : "default") + "_value2", (param2 != null ? param2 : "default") + "_value2" }};}
}
2.2.3 @Test
标记一个方法为测试方法
- 用法
/*** @Test 标记一个方法为测试方法* @Test(priority=1) 指定测试方法的优先级* @Test(alwaysRun=true) 指定测试方法始终运行* @Test(enabled=false) 禁用测试方法 false 禁用 true 启用* @Test(dependsOnMethods={"test1"}) 指定测试方法依赖于另一个测试方法* @Test(description="测试描述") 指定测试方法的描述* @Test(dataProvider="dataProvider") 指定测试方法使用的数据提供者* @Test(dataProviderClass=DataProviderClass.class) 指定测试方法使用的数据提供者和类 如果未指定,数据提供者将在当前测试方法的类或其基类之一上查找。如果指定了此属性,则数据提供程序方法需要在指定的类上是静态的。* @Test(dataProviderParameters={"param1", "param2"}) 指定测试方法使用参数* @Test(groups={"group1", "group2"}) 指定测试方法的组* @Test(timeOut=1000) 指定测试方法的超时时间* @Test(invocationCount=2) 指定测试方法的调用次数* @Test(invocationTimeOut=1000) 指定测试方法的调用超时时间* @Test(threadPoolSize=2) 指定测试方法的线程池大小* @Test(suiteName="suite1") 指定测试方法的套件名称* @Test(suiteNames={"suite1", "suite2"}) 指定测试方法的套件名称* @Test(suiteFile="suite.xml") 指定测试方法的套件文件* @Test(suiteFiles={"suite1.xml", "suite2.xml"}) 指定测试方法的套件文件* @Test(suiteXmlFiles={"suite1.xml", "suite2.xml"}) 指定测试方法的套* @Test(successPercentage=100) 指定测试方法的成功百分比* @Test(expectedExceptions=Exception.class) 指定测试方法的预期异常* @Test(expectedExceptionsMessageRegExp="error") 指定测试方法的预期异常消息正则表达式* @Test(expectedExceptions={Exception.class, IOException.class}) 指定测试方法的预期异常* @Test(expectedExceptionsMessageRegExp={"error1", "error2"}) 指定测试方法的预期异常消息正则表达式* @Test(expectedExceptions={Exception.class, IOException.class}, expectedExceptionsMessageRegExp={"error1", "error2"}) 指定测试方法的预期异常和消息正则表达式* @Test(expectedExceptions={Exception.class, IOException.class}, expectedExceptionsMessageRegExp={"error1", "error2"}, expectedExceptionsMessageRegExp={"error1", "error2"}) 指定测试方法的预期异常和消息正则表达式* @Test(singleThreaded=true) 指定测试方法的单线程执行* @Test(singleThreaded=false) 指定测试方法的多线程执行* @Test(singleThreaded=true, threadPoolSize=2) 指定测试方法的单线程执行和线程池大小* @Test(singleThreaded=false, threadPoolSize=2) 指定测试方法的多线程执行和线程池大小* @Test(singleThreaded=true, threadPoolSize=2, invocationCount=2) 指定测试方法的单线程执行、线程池大小和调用次数* @Test(singleThreaded=false, threadPoolSize=2, invocationCount=2) 指定测试方法的多线程执行、线程池大小和调用次数* @Test(singleThreaded=true, threadPoolSize=2, invocationCount=2, timeOut=1000) 指定测试方法的单线程执行、线程池大小、调用次数和超时时间**/
- 实例
@Testpublic void ignore1() {System.out.println("ignore1 运行了");}/*** 忽略测试* 使用 @Test 注解的参数 enabled 参数设置为 false可以忽略执行此测试方法* 此参数默认为 true*/@Test(enabled = false)public void ignore2() {System.out.println("ignore2 运行了");}@Test(enabled = true)public void ignore3() {System.out.println("ignore3 运行了");}@Testpublic void test1() {assertTrue(true);}@Testpublic void test2() {assertTrue(false);}/*** 依赖的使用示例* test3 依赖于 test1 和 test2* dependsOnMethods在被依赖的方法运行完成之后运行当前方法,如果依赖方法测试不通过,那么当前方法也不会继续运行了*/@Test(dependsOnMethods={"test1","test2"})public void test3() {assertTrue(true);}
2.2.3.1多线程测试
- 实例
public class demo9 {/*多线程测试之注解方式如果我们要对一个付款进行10万次压测,确保不能超过二十万秒线程测试,局限于测试机器的CPU性能检查执行结果,我们发现很多重复的数字,此时这个数字表示:同一时间有多个线程执行System.out.println(sum);代码进行打印操作但是我们定义的sum参数初始化为0,为什么没有输出1或者2呢,因为可能多个线程同时执行了sum++导致sum参数的值在执行System.out.println(sum);方法之前有多个线程执行了sum++ 导致的*//*** invocationCount 参数为执行次数* threadPoolSize 设置线程池的个数* timeOut 设置超时间时间 单位:ms*/private static int sum = 0;@Test(invocationCount = 10,threadPoolSize = 4,timeOut = 1000)public void test(){sum++;System.out.println(sum);// Thread.currentThread()方法返回当前正在执行的线程System.out.printf("Thread Id :%s%n",Thread.currentThread().getId());}
}
- 结合xml使用
public class demo10 {/*多线程测试之xml文件方式*/// 此处缺少多线程注解方式的测试@Testpublic void test1(){System.out.printf("Thread Id :%s%n",Thread.currentThread().getId());}@Testpublic void test2(){System.out.printf("Thread Id :%s%n",Thread.currentThread().getId());}@Testpublic void test3(){System.out.printf("Thread Id :%s%n",Thread.currentThread().getId());}}
<?xml version="1.0" encoding="UTF-8" ?><!--<suite name="thread" parallel="methods" thread-count="2">-->
<!--<suite name="thread" parallel="tests" thread-count="2">-->
<suite name="thread" parallel="classs" thread-count="2"><!--parallel 参数:methods 级别:所有用例都可以在不同的线程下执行tests 级别:相同的test tag下的用例只能在同一个线程中执行不同的test tag下的用例可以在不同的线程下执行thread-count:表示了最大并发线程数xml文件配置的这种方式不能指定线程池,只有方法上才可以指定线程池--><test name="demo1"><classes><class name="com.selenium.testcase.TestDemo.demo10"/></classes></test><test name="demo2"><classes><class name="com.selenium.testcase.TestDemo.demo10"/></classes></test></suite>
2.2.4 @Factory
public class demo12 {/*@Factory 注解方法允许在运行时根据某些数据集或条件创建测试该方法必须返回 Object [] 数组,其中每个元素都是一个测试实例。本来我们的Test只执行一次,但是我们用了我们的Factory注解进行配置这样子我们执行我们的Test的时候就会根据我们的Factory配置中,配置的执行两次,让我们的Test执行两次*/@Testpublic void testMethod(){System.out.println("Simple Test Method.");}@Factorypublic Object[] factoryMethod() {return new Object[]{new demo12(),new demo12()};}}
2.2.4.1 动态生成测试用例
public class demo12_1 {// 动态生成测试用例// createTests 方法返回三个 DynamicTestFactory 实例,每个实例传入不同的测试数据。private String testData;public demo12_1(String testData) {this.testData = testData;}@Testpublic void testMethod() {System.out.println("Test Data: " + testData);}@Factorypublic static Object[] createTests() {return new Object[]{new demo12_1("Data1"),new demo12_1("Data2"),new demo12_1("Data3")};}
}
2.2.4.2 结合参数化测试
public class demo12_2 {// 结合参数化测试// 结合 @Parameters 注解,从 TestNG 的 XML 配置文件中读取参数。// @Parameters 注解从 XML 配置中读取参数,传递给 createTests 方法private int value;public demo12_2(int value) {this.value = value;}@Testpublic void testMethod() {System.out.println("Value: " + value);}@Factory@Parameters({"param1", "param2"})public static Object[] createTests(int param1, int param2) {return new Object[]{new demo12_2(param1),new demo12_2(param2)};}
}
2.2.4.3 结合数据驱动测试
package com.selenium.testcase.TestDemo;import org.testng.annotations.DataProvider;
import org.testng.annotations.Factory;
import org.testng.annotations.Test;public class demo12_4 {/*结合数据驱动测试结合数据提供者( @DataProvider )动态生成测试用例。*/private String username;private String password;// 保留一个构造函数用于初始化实例变量public demo12_4(String username, String password) {this.username = username;this.password = password;}@Testpublic void loginTest() {System.out.println("Username: " + username + ", Password: " + password);}@DataProvider(name = "loginData")public static Object[][] provideData() {return new Object[][]{{"user1", "pass1"},{"user2", "pass2"}};}// 使用@Factory注解的应该是工厂方法,而非构造函数// 修改工厂方法返回类型为Object[]@Factory(dataProvider = "loginData")public static Object[] createInstances(String username, String password) {return new Object[]{new demo12_4(username, password)};}
}
2.2.5 @Listener
/*@Listener注解注解介绍@Listeners 注解在测试类上定义侦听器@Listeners 注释方法侦听某些事件并跟踪测试执行,同时在测试执行的每个阶段执行某些操作事件可以是任何事情,例如测试方法成功、测试方法失败、测试方法开始等监听器or接口以下是一些允许您修改 TestNG 行为的侦听器或接口:IAnnotationTransformer 允许动态修改测试方法的注解(如 @Test 、 @BeforeMethod 等 适用场景:运行时修改测试方法的属性(如 enabled 、 priority )。动态调整测试数据或参数。IAnnotationTransformer2 支持对配置方法(如 @BeforeSuite 、 @AfterTest )的注解进行修改。 适用场景: 动态修改配置方法的属性。IHookable 允许在测试方法执行之前和之后执行自定义代码。 适用场景: 在测试方法执行之前和之后执行自定义代码。IInvokedMethodListener IMethodInterceptor IReporterISuiteListenerITestListener*//*如何注册监听器?在你的测试类中,可以通过 @Listeners 注解注册监听器,或者在 testng.xml 中全局配置:<listeners><listener class-name="com.example.MyTestListener" /></listeners>@Listeners({监听器文件名.class})总结动态修改注解: IAnnotationTransformer 、 IAnnotationTransformer2方法拦截与顺序调整: IMethodInterceptor 、 IHookable生命周期监听: ITestListener 、 ISuiteListener 、 IInvokedMethodListener报告生成: IReporter*/
2.2.5.1 实例
package com.selenium.testcase.TestDemo;import org.testng.IAnnotationTransformer;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
import org.testng.annotations.ITestAnnotation;import java.lang.reflect.Constructor;
import java.lang.reflect.Method;public class demo13_1 implements ITestListener {@Overridepublic void onTestStart(ITestResult result) {System.out.println("测试开始了");}@Overridepublic void onTestSuccess(ITestResult result) {System.out.println("测试用例成功,其详情为:" + result.getName());}@Overridepublic void onTestFailure(ITestResult result) {System.out.println("测试用例失败,其详情为:" + result.getName());}@Overridepublic void onTestSkipped(ITestResult result) {System.out.println("测试用例被跳过,其详情为:" + result.getName());}@Overridepublic void onTestFailedButWithinSuccessPercentage(ITestResult result) {System.out.println("测试用例失败,但在成功百分比范围内,其详情为:" + result.getName());}@Overridepublic void onStart(ITestContext context) {System.out.println("整个测试开始前被调用");}@Overridepublic void onFinish(ITestContext context) {System.out.println("整个测试结束后被调用");}
}///*
//IAnnotationTransformer
//用途:允许动态修改测试方法的注解(如 @Test 、 @BeforeMethod 等)。
//适用场景:
//运行时修改测试方法的属性(如 enabled 、 priority )。
//动态调整测试数据或参数。
// */
//public class MyAnnotationTransformer implements IAnnotationTransformer {
// @Override
// public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
// annotation.setPriority(1); // 动态设置优先级
// }
//}
//
///*
//IAnnotationTransformer2
//用途:扩展 IAnnotationTransformer ,支持对配置方法(如 @BeforeSuite 、 @AfterTest )的注解进行修改。
//适用场景:
//动态修改配置方法的属性。
// */
//public class MyAnnotationTransformer2 implements IAnnotationTransformer2 {
// @Override
// public void transform(IConfigurationAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
// annotation.setEnabled(false); // 动态禁用配置方法
// }
//}
///*
//IHookable
//用途:允许在测试方法执行前后插入自定义逻辑。
//适用场景:
//在测试方法执行前后添加额外的操作(如日志记录、资源清理)。
// */
//public class MyHookable implements IHookable {
// @Override
// public void run(IHookCallBack callBack, ITestResult testResult) {
// System.out.println("Before test method");
// callBack.runTestMethod(testResult); // 执行测试方法
// System.out.println("After test method");
// }
//}
//
///*
//IInvokedMethodListener
//用途:监听测试方法的调用(包括配置方法和测试方法)。
//适用场景:
//记录方法调用的详细信息(如参数、返回值)。
// */
//public class MyInvokedMethodListener implements IInvokedMethodListener {
// @Override
// public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {
// System.out.println("Before invoking: " + method.getTestMethod().getMethodName());
// }
//}
//
///*
//IMethodInterceptor
//用途:拦截测试方法的执行顺序,动态调整测试方法的执行列表。
//适用场景:
//自定义测试方法的执行顺序。
// */
//public class MyMethodInterceptor implements IMethodInterceptor {
// @Override
// public List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context) {
// // 按方法名称排序
// methods.sort(Comparator.comparing(m -> m.getMethod().getMethodName()));
// return methods;
// }
//}
//
///*
//IReporter
//用途:生成自定义测试报告。
//适用场景:
//扩展默认的 TestNG 报告,生成更详细的测试结果。
// */
//public class MyReporter implements IReporter {
// @Override
// public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
// // 生成自定义报告
// }
//}
//
///*
//ISuiteListener
//用途:监听测试套件(Suite)的生命周期事件(如开始、结束)。
//适用场景:
//在套件执行前后执行初始化或清理操作。
// */
//public class MySuiteListener implements ISuiteListener {
// @Override
// public void onStart(ISuite suite) {
// System.out.println("Suite started: " + suite.getName());
// }
//}
//
///*
//ITestListener
//用途:监听测试方法(Test)的生命周期事件(如开始、成功、失败)。
//适用场景:
//记录测试结果、截图或日志。
// */
//public class MyTestListener implements ITestListener {
// @Override
// public void onTestFailure(ITestResult result) {
// System.out.println("Test failed: " + result.getName());
// }
//}
- 用例调用
package com.selenium.testcase.TestDemo;import org.testng.Assert;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;@Listeners({demo13_1.class}) // 使用Listener注解标记使用的监听器
public class demo13_2 {/*同时Listeners 监听器 实现测试每个阶段的操作*/@Testpublic void sum() {int sum = 0;int a = 15;int b = 27;sum = a + b;System.out.println("sum=" + sum);}@Testpublic void testtofail() {System.out.println("Test case has failed");Assert.assertTrue(false);}}
三、依赖测试
某测试方法的执行需要依赖于另一测试方法的执行。
使用示例:
@Test(dependsOnMethods = {"test2"})
public void test1() {System.out.println("test1()");
}@Test
public void test2() {System.out.println("test2()");
}
运行结果:
按照字典顺序应该test1()先执行,但是由于test1()依赖于test2(),所以test2()先执行:

public class demo5 {/*依赖测试应用场景:如果我们需要进行余额查询,然而余额查询又依赖登录后获取token值,则如果登陆失败我们就不用去执行获取余额的方法,可以节省大量时间*/@Testpublic void test1() {System.out.println("test1 run");}/*** 这个方法是报错的*/@Testpublic void test3() {System.out.println("test3 run");throw new RuntimeException();}/*** 我们此处执行单单只run test2 进行测试 会先去调用test1 然后再去调用test2* 如果被依赖的方法报错,则会出现失败测试,依赖运行报错方法的方法则会被直接忽略,不被执行**/@Test(dependsOnMethods = {"test1"})public void test2() {System.out.println("test2 run");}@Test(dependsOnMethods = {"test3"})public void test4() {System.out.println("test3 run");}}
四、忽略测试
执行某一测试类时忽略某一测试方法。
使用方法:@Test(enabled = false)
/*** 忽略测试* 使用 @Test 注解的参数 enabled 参数设置为 false可以忽略执行此测试方法* 此参数默认为 true*/@Test(enabled = false)public void ignore2() {System.out.println("ignore2 运行了");}@Test(enabled = true)public void ignore3() {System.out.println("ignore3 运行了");}
五、超时测试
某一测试方法执行的时间超过指定的毫秒数,则认为此方法执行失败并终止执行抛出异常:

使用方法:@Test(timeOut = 1000)
public class demo11 {/*超时测试*//**** timeOut参数设置了超时时间,单位为毫秒级别* 引用场景,一般我们可以设置某个测试的超时时间如果超长,则跳过此测试进行下一个用例执行** @throws InterruptedException 多线程异常抛出*/@Test(timeOut = 3000)public void testSuccess() throws InterruptedException {Thread.sleep(2000);System.out.println("超时测试");}@Test(timeOut = 2000)public void testFained() throws InterruptedException {Thread.sleep(3000);System.out.println("超时测试");}
}
六、异常测试
public class demo4 {// 异常测试/*** 我们在什么时候会用到异常测试呢?* 在我们期望结果是某个异常的时候** 比如:我们传入了某些不合法的参数,程序抛出了异常* 也就是说我们期望结果就是要抛出某个异常异常**//*** 这个是一个测试结果会失败的异常* 使用了 @Test(expectedExceptions = RuntimeException.class) 注解,表示期望该方法会抛出 RuntimeException 异常。* 结果对比:由于测试期望抛出 RuntimeException,但方法实际执行过程中没有抛出任何异常,因此测试结果为失败。*/@Test(expectedExceptions = RuntimeException.class)public void runTimeException(){System.out.println("这个是一个失败的异常测试");}/*** 这个是一个成功的异常测试**/@Test(expectedExceptions = RuntimeException.class)public void runTimeSuccess(){System.out.println("这个是一个成功的异常测试");// 我们new 一个异常让他抛出throw new RuntimeException();}
}
七、分组测试
可用于只想执行某一部分测试用例时使用。
-
定义测试方法并指定分组
@Test(groups = {"g1"}) public void test1() {System.out.println("g1分组的test1()方法执行"); }@Test(groups = {"g1"}) public void test2() {System.out.println("g1分组的test2()方法执行"); }@Test(groups = {"g2"}) public void test3() {System.out.println("g2分组的test3()方法执行"); } -
testng.xml文件中定义groups标签

-
运行结果

public class demo3 {// 分组测试 把测试方法进行分组,从而更加规范/*AfterGroups 和 BeforeGroups 注解用于在组运行之前和之后运行一些代码beforeGroupsOnServer 通常用于初始化测试环境或准备测试数据。AfterGroups 通常用于初始化测试环境或准备测试数据。这个是服务端组运行之前运行的方法这个是服务端组的测试方法1111这个是服务端组的测试方法2222这个是服务端组运行之后运行的方法这个是客户端组运行之前运行的方法这个是客户端组的测试方法3333这个是客户端组的测试方法4444这个是客户端组运行之后运行的方法*/@Test(groups = "server")public void test1() {System.out.println("这个是服务端组的测试方法1111");}@Test(groups = "server")public void test2() {System.out.println("这个是服务端组的测试方法2222");}@Test(groups = "client")public void test3() {System.out.println("这个是客户端组的测试方法3333");}@Test(groups = "client")public void test4() {System.out.println("这个是客户端组的测试方法4444");}@BeforeGroups("server")public void beforeGroupsOnServer() {System.out.println("这个是服务端组运行之前运行的方法");}@AfterGroups("server")public void afterGroupsOnServer() {System.out.println("这个是服务端组运行之后运行的方法");}@BeforeGroups("client")public void beforeGroupsOnClient() {System.out.println("这个是客户端组运行之前运行的方法");}@AfterGroups("client")public void afterGroupsOnClient() {System.out.println("这个是客户端组运行之后运行的方法");}}
七、失败重试机制
有时在测试过程中,可能会出现失败的情况,如果想要重试失败的测试方法就需要使用 TestNG 的失败重试机制。
7.1 IRetryAnalyzer接口
如果想要使用 TestNG 的失败重试机制,就必须了解此接口。
该接口的定义如下:
public interface IRetryAnalyzer {/*** 1. 如果测试方法需要重试则此方法返回true,否则返回false* 2. 参数result表示刚刚运行的测试方法的运行结果*/public boolean retry ( ITestResult result ) ;
}
经过配置之后,一旦测试方法失败,将调用此方法,可以从参数 result 中得到该测试方法的详细信息。如果要重新执行失败的测试,此方法实现应返回true,如果不想重新执行测试,则返回false。通常,此接口的实现类中定义重试的次数。
使用举例:
@Slf4j
public class RetryListener implements IRetryAnalyzer {//定义重试次数的初始值private int initReTryNum = 1;//定义最大重试次数private int maxReTryNum = 3;@Overridepublic boolean retry(ITestResult iTestResult) {if (initReTryNum <= maxReTryNum) {//组装error messageString message = "方法名: " + iTestResult.getName() + " " + "运行失败,正在进行第 " + initReTryNum + " 次重试";System.out.println(message);//重试次数+1 initReTryNum++;//还没有达到最大重试次数,继续重试return true;}return false;}
}
7.2 测试方法引入失败重试
7.2.1 通过注解的方式
该方式可以精确的指定某个测试方法进行失败重试。
在 @Test 注解的属性 retryAnalyzer 中指定 IRetryAnalyzer 的实现类。
使用举例:
public class Test {//此方法指定重试机制@Test(retryAnalyzer = RetryListener.class)public void test1() {Assert.assertEquals(false, true);}//此方法没有指定失败重试@Testpublic void test2() {Assert.assertEquals(false, true);}
}
运行结果:
只有 test1() 进行了指定次数的重试,因为仅在 test1() 的 @Test 注解中指定了 IRetryAnalyzer 的实现类,test2() 仅执行一次,因为没有在 test2() 的 @Test 注解中指定 IRetryAnalyzer 的实现类。

7.2.2 通过实现接口 + 监听器的方式
需要实现 ITestAnnotationTransformer 接口,会自动的在测试运行期间为每个测试方法调用重写的 transform 方法。也就是说,这种方式会为所有测试方法设置失败重试。
使用举例:
-
实现
ITestAnnotationTransformer接口import org.testng.internal.annotations.IAnnotationTransformer; import java.lang.reflect.Method;public class OverrideIAnnotationTransformer implements IAnnotationTransformer{@Overridepublic void transform(ITestAnnotation iTestAnnotation, Class aClass, Constructor constructor, Method method) {IRetryAnalyzer iRetryAnalyzer= iTestAnnotation.getRetryAnalyzer();if(iRetryAnalyzer==null){//设置指定的IRetryAnalyzer接口的实现类iTestAnnotation.setRetryAnalyzer(RetryListener.class);} } } -
配置 testng.xml 的监听器
<suite name="All Test Suite"><listeners><!-- 定义IAnnotationTransformer的实现类 --><listener class-name="com.qizegao.interfacetest.OverrideIAnnotationTransformer"/></listeners><test verbose="2" preserve-order="true" name="F:/InterfaceTest"><classes><class name="com.qizegao.test.Test001"/></classes></test> </suite> -
运行结果
这次没有任何
@Test注解定义retryAnalyzer属性,但是可以发现所有的测试方法都会进行失败重试。
