51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 2757|回复: 1
打印 上一主题 下一主题

如何解决TestNG Retry的问题

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2012-9-11 14:09:56 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我们使用TestNG来作为自动化测试框架的基础。在运行一批test case之后呢,我们希望能够自动Retry failed的test case。TestNG提供了一个IRetryAnalyzer的接口,在@Test annotation里面可以指定使用Retry类来执行retry的功能。

@Test(retryAnalyzer = TestRetryAnalyzer.class)



TestRetryAnalyzer类实现了IRetryAnalyzer接口。

实现逻辑为:在retry方法里,判断Retry次数是否已经超过指定的最大retry次数。如果没有返回true,否则返回false。

_______________________________________________________________________________

import org.testng.IRetryAnalyzer;

import org.testng.ITestResult;



public class TestRetryAnalyzer implements IRetryAnalyzer {

        private static final String TEST_RETRY_COUNT = "testRetryCount";

        private int count = 1;

        private int maxCount = 1;



        public TestRetryAnalyzer() {

                  String retryMaxCount = System.getProperty(TEST_RETRY_COUNT);

                  if (retryMaxCount != null) {

                           maxCount = Integer.parseInt(retryMaxCount);

                  }

        }



        public int getCount() {

                  return this.count;

        }

        

        public int getMaxCount() {

                  return this.maxCount;

        }

        

        public synchronized boolean retry(ITestResult result) {

                  String testClassName = String.format("%s.%s", result.getMethod()

                                    .getRealClass().toString(), result.getMethod().getMethodName());

                  

                  if (count <= maxCount) {

                           result.setAttribute("RETRY", new Integer(count));



                           Logging.log("[RETRYING] " + testClassName + " FAILED, "

                                              + "Retrying " + count + " time", true);



                           count += 1;

                           return true;

                  }

                  return false;

        }

}

_______________________________________________________________________________



然后,我们需要定义一个TestNGListener,来处理TestCase Retry的状态。在onTestFailure方法里,未达到最大retry次数的失败Case,我们把它的状态设置为SKIP,这样TestNG不会把它统计为Failed的test case。



在OnFinish方法里面处理最后TestCase的Result。



public class RetryTestListener extends TestListenerAdapter {



publicsynchronizedvoidonTestFailure(ITestResult arg0) {

      if(arg0.getMethod().getRetryAnalyzer() !=null) {

          TestRetryAnalyzer testRetryAnalyzer = (TestRetryAnalyzer) arg0.getMethod().getRetryAnalyzer();

         

          if(testRetryAnalyzer.getCount() <= testRetryAnalyzer.getMaxCount()) {

             arg0.setStatus(ITestResult.SKIP);

             Reporter.setCurrentTestResult(null);

          }

          else

             failedCases.addResult(arg0, arg0.getMethod());



          isRetryHandleNeeded=true;

      }

   }



public void onFinish(final ITestContext arg0) {

if(isRetryHandleNeeded)

      {

          removeIncorrectlySkippedTests(arg0,failedCases);

          removeFailedTestsInTestNG(arg0);

      }else

      {

          skippedCases= arg0.getSkippedTests();

          failedCases= arg0.getFailedTests();

      }

      

   }



TestNG可能会把TestCase同时放在Skipped和Failed里面,所以我们在Skipped的testcase里面剔除真正Failed的Test Case(最后一次Retry失败的Case)



protectedIResultMapremoveIncorrectlySkippedTests(ITestContext test,IResultMap map)

   {   

    List<ITestNGMethod> failsToRemove =newArrayList<ITestNGMethod>();

    IResultMap returnValue = test.getSkippedTests();



    for(ITestResult result : returnValue.getAllResults())

    {

      for(ITestResult resultToCheck : map.getAllResults())

      {

          if(resultToCheck.getMethod().equals(result.getMethod()))

          {

              failsToRemove.add(resultToCheck.getMethod());

              break;

          }

      }   

      for(ITestResult resultToCheck : test.getPassedTests().getAllResults())

      {

          if(resultToCheck.getMethod().equals(result.getMethod()))

          {

              failsToRemove.add(resultToCheck.getMethod());

              break;

          }

      }   

    }

   

    for(ITestNGMethod method : failsToRemove)

    {

        returnValue.removeResult(method);

    }

    skippedCases= returnValue;

   

   

    returnreturnValue;

   }



IResultMap只提供了删除某个方法的removeResult(Method)方法,如果使用了Dataprovider,我们不能直接调用此方法在FailedResult里面直接删除该方法的结果。这会造成test case结果的混淆。同一个TestMethod可能一个Data的结果Pass,另一个Data的结果Failed。所以我们使用failedCases来记录真正失败的result。同时我们在自己的Report中把FailedCases显示出来。
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

该用户从未签到

2#
 楼主| 发表于 2012-9-11 14:11:31 | 只看该作者
在下面这个方法里面,我们在failedTests里面查找,如果failedCases里面没有该方法,就把该方法的结果删除掉。这样确保TestNG能够报告Suite的整体Pass/Fail状态。有些同学问,为什么要这么做?我们之前不是把testcase设置为skip了么?还记得我们前面提过的,TestNG可能会把result放在两个Map里面了,所以还是需要做这一步来确保正确。

private void removeFailedTestsInTestNG(ITestContext test)
        {     
          IResultMap returnValue = test.getFailedTests();
          
         
          for(ITestResult result : returnValue.getAllResults())
          {
               
            boolean isFailed = false;
            
            for(ITestResult resultToCheck : failedCases.getAllResults())
            {
                if(result.getMethod().equals(resultToCheck.getMethod()))
                {
                        System.out.println("Passed:"+result.getMethod().getMethodName());
                        isFailed = true;
                    break;
                }
            }
            if(!isFailed)
            {
                    returnValue.removeResult(result.getMethod());
                    test.getFailedConfigurations().removeResult(result.getMethod());
            }
          }
          
        }

}

我们这么做了之后,基本能够保证报告的正确性。但是TestNG的Retry对DataProvider的支持不够好,详情参考 https://groups.google.com/forum/ ... shqivk/R0dCG14kSccJ
回复 支持 反对

使用道具 举报

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

GMT+8, 2024-11-27 18:01 , Processed in 0.066345 second(s), 28 queries .

Powered by Discuz! X3.2

© 2001-2024 Comsenz Inc.

快速回复 返回顶部 返回列表