写点什么

TestNG 测试用例重跑详解及实践优化

  • 2020-05-26
  • 本文字数:4369 字

    阅读完需:约 14 分钟

TestNG测试用例重跑详解及实践优化

AI 大模型超全落地场景&金融应用实践,8 月 16 - 19 日 FCon x AICon 大会联诀来袭、干货翻倍!

测试用例运行稳定性是自动化质量的一个重要指标,在运行中需要尽可能的剔除非 bug 造成的测试用例执行失败,对于失败用例进行重跑是常用策略之一。一种重跑策略是所有用例运行结束后对失败用例重跑,另一种重跑策略是在运行时监控用例运行状态,失败后实时重跑。


下面,详细介绍 TestNG 如何对失败测试用例实时重跑并解决重跑过程中所遇到问题的实践和解决方案。对失败测试用例进行实时重跑,有以下几个方面需求:


  1. 测试用例运行失败,监听到失败后立即进行重跑

  2. 测试用例通过 dependsOnMethods/dependsOnGroups 标记依赖其他测试用例,在被依赖的测试用例重跑运行成功后,该测试用例可以继续运行

  3. 对于重跑多次的测试用例,只记录最后一次运行成功或失败结果

一、测试用例重跑

1.1 retryAnalyzer 注解方式

对于希望测试用例中的少量易失败,不稳定的测试用例进行重跑,可采用这种方式。

1.1.1 原理

以下是 TestNG 处理测试用例运行结果的部分代码。


IRetryAnalyzer retryAnalyzer = testMethod.getRetryAnalyzer();boolean willRetry = retryAnalyzer != null && status == ITestResult.FAILURE && failure.instances != null && retryAnalyzer.retry(testResult);if (willRetry) {  resultsToRetry.add(testResult);  failure.count++;  failure.instances.add(testResult.getInstance());  testResult.setStatus(ITestResult.SKIP);} else {  testResult.setStatus(status);  if (status == ITestResult.FAILURE && !handled) {    handleException(ite, testMethod, testResult, failure.count++);  }
复制代码


分析以上代码,其中,接口 IretryAnalyzer 的方法 retry()的返回值作为是否对失败测试用例进行重跑的一个条件。如果 retry()结果为 true,则该失败测试用例会重跑,同时将本次失败结果修改为 Skip;如果结果为 false,则失败的测试用例保持失败结果,运行结束。因此,如果你希望失败测试用例重跑的话,需要把 IretryAnalyzer 的 retry()方法重写,插入自己定义的逻辑,设置返回值为 true。

1.1.2 代码

创建类 RetryImpl,重写 retry()方法,设置失败测试用例的重跑次数,代码如下:


public class RetryImpl implements IRetryAnalyzer {    private int count = 1;    private int max_count = 3;   // Failed test cases could be run 3 times at most    @Override    public boolean retry(ITestResult result) {        System.out.println("Test case :"+result.getName()+",retry time: "+count+"");        if (count < max_count) {            count++;            return true;        }        return false;    }}
复制代码

1.1.3 实例

public class TestNGReRunDemo {    @Test(retryAnalyzer=RetryImpl.class)    public void test01(){        Assert.assertEquals("success","fail");        System.out.println("test01");    }}
复制代码


以上测试用例 test01 可重复运行 3 次。

1.2 实现接口 IAnnotationTransformer 方式

如果希望所有失败的测试用例都进行重跑,采用 retryAnalyzer 注解方式对每个测试用例进行注解就比较麻烦。通过实现 IAnnotationTransformer 接口的方式,可以对全量测试用例的重试类进行设置。该接口是一个监听器接口,用来修改 TestNG 注解。IAnnotationTransformer 监听器接口只有一个方法:transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod). 上文中,我们自定义了类 RetryImpl 实现接口 IRetryAnalyzer。TestNG 通过 transfrom()方法修改 retryAnalyzer 注解。以下代码对 retryAnalyzer 注解进行修改设置

1.2.1 代码

创建类 RetryListener,代码如下。


public class RetryListener implements IAnnotationTransformer {
public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
IRetryAnalyzer retry = annotation.getRetryAnalyzer(); if (retry == null) { annotation.setRetryAnalyzer(RetryImpl.class); } }}
复制代码

1.2.2 配置 Listener

TestNG 可以在配置文件或者测试类中对Listener类进行配置。


  • 方法一:在 TestNG 的配置 XML 中进行以下配置

  • 方法二:在测试类中通过 @Listeners 配置


@Listeners({RetryListener.class})public class TestNGReRunDemo {    @Test    public void test01(){        Assert.assertEquals("success","fail");        System.out.println("test01");    }}
复制代码


配置完成后,运行测试用例 test01,运行结果显示 test01 将重跑次数 3 次。

二、被依赖的测试用例重跑结果处理

进一步分析 TestNG 的运行代码,其在对失败运行用例重跑时,逻辑如下图。



对于通过 dependsOnMethods 或 dependsOnGroups 注解依赖于其他测试用例的测试用例来讲 ,测试用例执行分为两种情况:


  • alwaysRun=true: 则无论所依赖的测试用例执行情况如何,该测试用例都会执行, 即所依赖的测试用例重跑不会影响该测试用例的执行

  • alwaysRun=false: 或者保持缺省值(false),依赖于其他测试用例或测试用例组的测试结果,在运行时 TestNG 获取所依赖的测试用例的运行结果,检查依赖的测试用例是否全部执行成功,如果不全部成功,则 把该测试用例结果设置为 Skipped

2.1 场景分析:场景一

被依赖的测试用例失败后进行了重跑,并重跑成功。(注:在 RetryImpl 类中,已设置最大重跑次数 max_count = 3


public static int number =0;
@Testpublic void test01(){number++;System.out.println(String.valueOf(number));Assert.assertEquals(number,2); System.out.println("test01");}
@Test(dependsOnMethods = "test01") // alwaysRun = false by defaultpublic void test02(){ System.out.println("test02 is running only if test01 is passed.");}
复制代码


1、TestNG 测试报告



2、问题


测试用例运行次数运行情况测试报告
Test012第一次:skipped ; 第二次:passed在Skipped 和Passed的统计数量中,test01被分别记录一次
Test020Skipped记录一次Skipped


  • 测试报告: test01 运行结果全部被记录,而用例重跑,只希望记录最后的结果。

  • 运行情况: 测试用例 test02 依赖于测试用例 test01 运行结果,在 test01 重跑成功后,测试用例 test02 没有执行,不符合需求预期

2.2 场景分析:场景二

被依赖的测试用例失败后进行了重跑,并且重跑没有成功。(注:在 RetryImpl 类中,已设置最大重跑次数 max_count = 3)


public static int number =0;@Testpublic void test01(){number++;System.out.println(String.valueOf(number));Assert.assertEquals(number,10);    System.out.println("test01");}
@Test(dependsOnMethods = "test01") // alwaysRun = false by defaultpublic void test02(){ System.out.println("test02 is running only if test01 is passed.");}
复制代码


1、TestNG 测试报告



2、问题


测试用例运行次数运行结果测试报告
Test013第一次:skipped;第二次:skipped;第三次:failed在Skipped统计数量中,test01被被记录两次在failed统计中,test01被记录一次
Test020Skipped记录一次Skipped


  • 运行情况: 测试用例 test02 依赖于测试用例 test01 运行结果, 在 test01 重跑失败后,测试用例 test02 没有执行,这种情况符合需求预期

  • 测试报告: 同场景一,test01 重跑失败,运行结果全部被记录,而用例重跑,只希望记录最后的结果。

三、优化解决方案

以下方案解决重跑测试用例成功后后继测试用例无法继续运行的问题,并对测试报告进行优化。

3.1 TestListenerAdapter 方法重写

根据上面分析的 TestNG 逻辑,在对依赖测试用例的结果进行检查如果忽略重跑的中间结果只检查最后一次的运行结果,可以达到需求的。对于测试报告,同样的处理方式,忽略所有中间的测试用例运行结果,只记录最后结测试用例的中间运行结果为 Skipped,下面的代码通过重写 TestListenerAdapter 的 onTestSuccess()和 onTestFailure()方法,对测试用例的中间结果 skipped 进行了。代码如下:


public class ResultListener extends TestListenerAdapter {    @Override    public void onTestFailure(ITestResult tr) {        if(tr.getMethod().getCurrentInvocationCount()==1)        {            super.onTestFailure(tr);            return;        }
processSkipResult(tr); super.onTestFailure(tr); } @Override public void onTestSuccess(ITestResult tr) { if(tr.getMethod().getCurrentInvocationCount()==1) { super.onTestSuccess(tr); return; } processSkipResult(tr); super.onTestSuccess(tr); } // Remove all the dup Skipped results public void processSkipResult(ITestResult tr) { ITestContext iTestContext = tr.getTestContext(); Iterator<ITestResult> processResults = iTestContext.getSkippedTests().getAllResults().iterator(); while (processResults.hasNext()) { ITestResult skippedTest = (ITestResult) processResults.next(); if (skippedTest.getMethod().getMethodName().equalsIgnoreCase(tr.getMethod().getMethodName()) ) { processResults.remove(); } } }}
复制代码

3.2 配置结果处理 Listener 类

在配置文件进行全局设置或者在测试类中标记。


  • 方法一:在 TestNG 的配置 XML 中进行以下配置

  • 方法二:在测试类中通过 @Listeners 配置

3.3 场景一

1、 结果验证



2、结果分析


测试用例运行次数运行结果测试报告
Test012第一次:skipped;第二次:passed只在Passed的统计数量中test01被记录一次
Test021Passed记录一次passed

3.4 场景二

1、结果验证



2、结果分析


测试用例运行次数运行结果测试报告
Test013第一次:skipped;第二次:skipped;第三次:failedtest01只在failed统计中被记录一次
Test021Skipped依赖用例执行失败,test02结果为Skipped,只记录一次结果Skipped


本文转载自公众号宜信技术学院(ID:CE_TECH)。


原文链接


https://mp.weixin.qq.com/s/PLF-1RXbMPU1mWpOwiSamA


2020-05-26 10:001635

评论

发布
暂无评论
发现更多内容

两将军问题和TCP三次握手

有态度的马甲

TCP协议 两将军问题

【iOS逆向】某运营商签名算法分析

小陈

逆向思维 逆向 iOS逆向 逆向分析

智能合约系统开发Web3.0实现核心

薇電13242772558

智能合约

实时云渲染的关键技术是什么?

Finovy Cloud

人工智能 云渲染 实时渲染

【Nacos源码之配置管理 九】客户端获取配置数据的流程

石臻臻的杂货铺

nacos 10月月更

Surpass Day——Java 接口在开发中的作用、关于Object类、内部类

胖虎不秃头

Java 10月月更 se

Zebec即将推出公链并开放节点申请,潜力几何?

西柚子

如何从InfluxDB/OpenTSDB无缝连接到TDengine

TDengine

数据库 tdengine 开源 时序数据库

_fitoa_word的实现:一个整型数据是如何转成字符串的呢?

桑榆

源码刨析 10月月更 C++

【愚公系列】2022年10月 Go教学课程 023-Go容器之列表

愚公搬代码

10月月更

Surpass Day——Java 抽象类和接口

胖虎不秃头

Java 10月月更 se

如何快速打造BI大屏进行数据赋能

力软低代码开发平台

DAG 任务调度与 go-streams 结合的应用实践

KaiwuDB

GitLab + Jenkins + Harbor 工具链快速落地指南

胡说云原生

DevOps gitlab cicd Harbor jenkins

面试突击89:事务隔离级别和传播机制有什么区别?

王磊

Flowable 中 ReceiveTask 怎么玩?

江南一点雨

Java springboot workflow flowable JavaEE

数据结构学习,栈篇(顺序栈)

IC00

数据结构 算法 学习笔记 10月月更

leetcode 145. Binary Tree Postorder Traversal 二叉树的后序遍历 (中等)

okokabcd

LeetCode 数据结构与算法

【一Go到底】第九天---进制

指剑

Go golang 10月月更

使用最小花费爬楼梯

掘金安东尼

算法 10月月更

网络安全漏洞分析之远程代码执行

网络安全学海

黑客 网络安全 信息安全 渗透测试 漏洞挖掘

具有资质的昆明等保测评公司新名单看这里!

行云管家

等保 堡垒机 等级保护

如何低成本实现客户服务自动化?

Baklib

zookeeper-四字监控命令和工具

zarmnosaj

10月月更

Linux性能问题分析流程与性能优化思路

五分钟学大数据

Linux 10月月更

C语言中的内存模型

C++后台开发

内存模型 C语言 C/C++ linux开发 C++开发

【荣耀帐号服务FAQ】AuthorizationCode有效期是多久?

荣耀开发者服务平台

手机 服务 安卓 荣耀 honor

Vue3入门指北(十二)模板引用

Augus

Vue 3 10月月更

Surpass Day——IntelliJ IDEA和eclipse的使用、super关键字

胖虎不秃头

Java 10月月更 se

Vue网站自动提交百度链接

源字节1号

软件开发 后端开发 Vue网站

ESP32-C3 应用程序的启动流程

矜辰所致

ESP32-C3 10月月更 ESP-IDF

TestNG测试用例重跑详解及实践优化_软件工程_耿燕飞_InfoQ精选文章