TestNG测试用例重跑详解及实践优化-阿里云开发者社区

开发者社区> 宜信技术学院> 正文

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

简介:
+关注继续查看

测试用例运行稳定性是自动化质量的一个重要指标,在运行中需要尽可能的剔除非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>
    <listener class-name="PackageName.RetryListener"></listener>
</listeners>
  • 方法二在测试类中通过@Listeners配置
@Listeners({RetryListener.class})   
public class TestNGReRunDemo {
    @Test
    public void test01(){
        Assert.assertEquals("success","fail");
        System.out.println("test01");
    }
}

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

第二部分 被依赖的测试用例重跑结果处理

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

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

  • alwaysRun=true,则无论所依赖的测试用例执行情况如何,该测试用例都会执行,即所依赖的测试用例重跑不会影响该测试用例的执行。
  • alwaysRun=false,或者保持缺省值(false),依赖于其他测试用例或测试用例组的测试结果,在运行时TestNG获取所依赖的测试用例的运行结果,检查依赖的测试用例是否全部执行成功,如果不全部成功,则把该测试用例结果设置为Skipped。

2.1 场景分析:场景一

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

public static int number =0;

@Test
public void test01(){
number++;
System.out.println(String.valueOf(number));
Assert.assertEquals(number,2);
    System.out.println("test01");
}

@Test(dependsOnMethods = "test01")    // alwaysRun = false by default
public void test02(){
    System.out.println("test02 is running only if test01 is passed.");
}

1、TestNG测试报告

2、问题

测试用例 运行次数 运行情况 测试报告
Test01 2 第一次:skipped ; 第二次:passed 在Skipped 和Passed的统计数量中,test01被分别记录一次
Test02 0 Skipped 记录一次Skipped
  • 测试报告:test01运行结果全部被记录,而用例重跑,只希望记录最后的结果。
  • 运行情况:测试用例test02依赖于测试用例test01运行结果,在test01重跑成功后,测试用例test02没有执行,不符合需求预期。

2.2 场景分析:场景二

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

public static int number =0;
@Test
public void test01(){
number++;
System.out.println(String.valueOf(number));
Assert.assertEquals(number,10);     
    System.out.println("test01");
}

@Test(dependsOnMethods = "test01")    // alwaysRun = false by default
public void test02(){
    System.out.println("test02 is running only if test01 is passed.");
}

1、TestNG测试报告

2、问题

测试用例 运行次数 运行结果 测试报告
Test01 3 第一次:skipped;第二次:skipped;第三次:failed 在Skipped统计数量中,test01被被记录两次在failed统计中,test01被记录一次
Test02 0 Skipped 记录一次Skipped
  • 运行情况:测试用例test02依赖于测试用例test01运行结果,在test01重跑失败后,测试用例test02没有执行,这种情况符合需求预期。
  • 测试报告:同场景一,test01重跑失败,运行结果全部被记录,而用例重跑,只希望记录最后的结果。

第三部分 优化解决方案

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

3.1 TestListenerAdapter方法重写

根据上面分析的TestNG逻辑,在对依赖测试用例的结果进行检查时,如果忽略重跑的中间结果只检查最后一次的运行结果,可以达到需求的目的。对于测试报告,同样的处理方式,忽略所有中间的测试用例运行结果,只记录最后结果。
测试用例的中间运行结果为Skipped,下面的代码通过重写TestListenerAdapteronTestSuccess()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>
    <listener class-name="PackageName.ResultListener"></listener>
</listeners>
  • 方法二:在测试类中通过@Listeners配置
@Listeners({ResultListener.class})   
public class TestNGReRunDemo {
    @Test
    public void test01(){
        Assert.assertEquals("success","fail");
        System.out.println("test01");
    }
}

3.3 场景一

1、 结果验证

2、结果分析:

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

3.4 场景二

1、结果验证

2、结果分析:

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

作者:耿燕飞

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
9497 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,大概有三种登录方式:
2930 0
指令级, ns级优化实例, 怎么做到调无可调
这几天在做性能的优化, 主要是在kernel的调度模块加了信息采集, 导致延迟增加了100ns, 在经过一系列的优化之后, 延迟较少到了50ns, 不过在检查最后汇编代码的时候 发现有个地方gcc工作得不是很好, 仔细研究了一下. 以下是记录 ``` c代码 void memdelay_enqueue_task(struct task_struct *p, int flags) {
1317 0
非io优化实例CentOS 7系统 4G内存 free -m 显示内存3.5g左右
非io优化实例CentOS 7系统 4G内存 free -m 显示内存3.5g左右
4318 0
如何降低90%Java垃圾回收时间?以阿里HBase的GC优化实践为例
GC一直是Java应用中讨论的一个热门话题,尤其在像HBase这样的大型在线存储系统中,大堆下(百GB)的GC停顿延迟产生的在线实时影响,成为内核和应用开发者的一大痛点。
8759 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13186 0
PostgreSQL cluster大幅减少nestloop离散IO的优化方法
背景 对于较大数据量的表,如果在索引字段上面有小结果集JOIN,用nestloop JOIN是比较好的方法。 但是nestloop带来的一个问题就是离散IO,这个是无法回避的问题,特别是硬件IO能力不行的情况下,性能会比较糟糕。 有什么优化方法呢? PostgreSQL提供了一个
3288 0
《OpenACC并行程序设计:性能优化实践指南》一 1.2 简单的任务并行示例
本节书摘来自华章出版社《OpenACC并行程序设计:性能优化实践指南》一 书中的第1章,第1.2节,作者:[美] 罗布·法伯(Rob Farber),更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1180 0
Android ListView性能优化,异步加载图片
版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/lyhhj/article/details/48184383 ListView性能优...
894 0
+关注
宜信技术学院
宜信技术学院是宜信旗下的金融科技能力展示与输出平台。通过分享在金融科技领域的开源成果、研发实践促进金融科技生态圈企业创新升级。
129
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载