• 0
  • 0
分享
  • TestNG测试用例重跑详解及实践优化——软件测试圈
  • TIMI 2021-09-29 11:17:38 字数 6810 阅读 921 收藏 0
测试用例运行稳定性是自动化质量的一个重要指标,在运行中需要尽可能的剔除非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的运行代码,其在对失败运行用例重跑时,逻辑如下图。 

1.png

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

  • 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.png

2、问题

测试用例运行次数运行情况测试报告
Test012第一次:skipped ; 第二次:passedSkipped 和Passed的统计数量中,test01被分别记录一次
Test020Skipped记录一次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测试报告

3.png

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>
    <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、   结果验证

11.png

2、 结果分析:

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

3.4 场景二

1、 结果验证

5.png

2、 结果分析:

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


作者:宜信技术学院

原文链接:http://blog.itpub.net/69918724/viewspace-2690039/

  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          •   因项目组需求,需要更换一套Redis集群,为减少开发工作量,调研了一些Redis数据迁移工具,后决定使用Redis-Shake进行集群数据迁移,前期进行了一些测试。  本文主要包括两部分内容:  ·Redis集群搭建和模拟数据初始化:为了模拟生产环境的新旧两套Redis集群,首先在本机上进行环境的搭建,并准备迁移所需要的测试数据。  ·Redis-Shake测试:测试利用Redis-Shake进行数据迁移。  Redis集群搭建  在本部分,首先搭建一套3主3备的集群作为源集群,然后搭建一套5主5备的集群作为目标集群。为了简便起见,我们采用Docker来简化部署。  配置文件准备  首先,...
            0 0 1365
            分享
          •   见习测试工程师  任职要求:  1.应往届理工科毕业生,有志于在IT行业发展。  2.计算机相关专业;  3.有计算机语言者优先,如:C语言、C++、Java、.Net等。  初级测试工程师  任职要求:  1.一年以上软件测试经验,熟悉各种测试方法、测试工具、测试流程;  2.本科及以上学历,计算机相关专业;  3.有较强的分析问题能力和文字表达能力,逆向思维好;能完成测试方案、测试案例、测试报告的编写;  4.热爱软件测试工作,可以胜任重复性工作;  5.具有较强的沟通理解能力和协调能力,对工作积极主动、认真负责;  中级测试工程师  任职要求:  1.三年以上软件测试工作经验;  2...
            0 0 3582
            分享
          •   对业务指标的要求主要有:请求响应时间,最大并发量等等。  对系统资源的指标,如:资源使用率是指在系统负载运行期间,数据库服务器,应用服务器,web服务器的cpu,内存,硬盘,外置存储,网络带宽的使用率,低于20%的使用率为资源使用稳定,60%-80%的使用率表示资源使用饱和,超过80%的使用率的资源使用率必须尽快进行资源调整和优化。  1) 业务指标  2) 系统资源指标  根据测试目的不同,需要统的系统资源指标也不同。主要包括以下一些:服务器操作系统资源使用情况,各种服务器的资源消耗情况等等。  内存  Paging rate:内存页交换速率  如果该值偶尔走高,表明当前有线程竞争内存。...
            0 0 1118
            分享
          •   摘要:性能测试通过自动化的测试工具模拟正常、异常场景来对系统的各项性能指标进行测试。通过性能测试可以分析一个系统能力、瓶颈、关键问题等。本文结合直播平台的部分场景,使用开源SRS-Bench工具对直播并的4个场景进行压力测试,测试直播平台的基础能力。  一 、性能测评工具简介  性能测试范围较广,包含负载测试、压力测试等,负载测试可以确定在满足性能指标情况下,系统能承受的最大负载,压力测试可以确定在什么负载条件下系统性能处于失效状态,获得系统能提供的最大的服务级别,一般系统上线前均会进行性能测试。目前,较常用的性能测试工具分为商业测试工具、开源测试工具,较为常用的是Loadrunner及J...
            0 0 10711
            分享
          • 当我们聊起性能测试的时候,有人一定会说我们用的是loadrunner做性能,诚然,我们在进行性能测试工作的过程中,需要借助工具的辅助来帮我们完成一些工作,但loadrunner并不等于性能测试,或者说,性能测试工具不等于性能测试,工具永远是一种辅助的工具,而不能认为会用工具就会性能测试了!希望看到这里的童鞋,能够改变这种观念。下面,就说说一个完整的性能测试过程吧。一、准备工作1、系统基础功能验证性能测试在什么阶段适合实施?切入点很重要!一般而言,只有在系统基础功能测试验证完成、系统趋于稳定的情况下,才会进行性能测试,否则性能测试是无意义的。2、测试团队组建根据该项目的具体情况,组建一个几人的性...
            2 6 4175
            分享
      • 51testing软件测试圈微信