zoukankan      html  css  js  c++  java
  • testNG retry 失败的testcase只需要在xml中配置一个listener即可

    问题情况                                                 

    先说下问题情况,最近在做testNG与selenium集成做自动化测试的问题。

    因为如果将testNG做UI 测试的话,很多情况下可能测试是失败的,但是这些失败可能是一些其他的问题导致的,可能是脚本的问题或者是网络环境不稳定导致的,所以我们需要重新尝试运行这个失败的测试用例。

    testNG倒是没有直接的retry testcase的功能,不过它却提供了很多的接口,我们可以实现这些接口来得到retry的效果。

    在google上看到淘宝的QA项目组采用Ruby语言将testNG的源代码修改了retry的功能,然后又重新build后这样做的。这是一个solution,但是我不推荐。原因有两个:

    1,修改的jar包是针对指定的testNG版本的,所以如果我们需要体验testNG的新版本功能,这个jar可能就需要在源码基本上重新build有点 不太合适,详细地址是:https://github.com/NetEase/Dagger/wiki/Retry-Failed-Or-Skipped-Testcases

    2,该种修改的方法只能使用在testcase级别上,如果需要针对所有的testNG的testsuite都是用这种特性,可能就需要每个testcase都表明他们是使用这个retry功能,有点代码亢余。像这样在testcase中声明retry的类:

    import org.apache.log4j.Logger;
    import org.testng.Assert;
    import org.testng.annotations.Test;
    
    import com.hp.baserunner.RetryFail;
    import com.hp.pop.DemoPage;
    
    public class DemoRun {
    
        private static Logger log=Logger.getLogger(DemoRun.class);
        @Test(retryAnalyzer=RetryFail.class)// 这里声明retry的类,可以看到如果这样每个testcase可能都需要这样做,代码是不是有点多啊 :(
        public void demoTest()
        {
            DemoPage dp=new DemoPage();
            dp.demoTest();
        }
        @Test
        public void demoTest2()
        {
            DemoPage dp2=new DemoPage();
            dp2.demoTest2();
        }
    }
    既然是框架这样写肯定就有点不太合适了。
    框架设计使用                                         
    testNG中的对应的提供这些功能的接口有这些:

    Interface IRetryAnalyzer   这个就是retrytestcase的一个接口,然后impletment这个接口后实现相应的方法即可:

    有一个类 RetryAnalyzerCount  已经实现了以上的这个接口的方法:

    package org.testng.util;
    
    import org.testng.IRetryAnalyzer;
    import org.testng.ITestResult;
    
    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * An implementation of IRetryAnalyzer that allows you to specify
     * the maximum number of times you want your test to be retried.
     * 
     * @author tocman@gmail.com (Jeremie Lenfant-Engelmann)
     */
    public abstract class RetryAnalyzerCount implements IRetryAnalyzer {
    
      // Default retry once.
      AtomicInteger count = new AtomicInteger(1);
    
      /**
       * Set the max number of time the method needs to be retried.
       * @param count
       */
      protected void setCount(int count) {
        this.count.set(count);
      }
    
      /**
       * Retries the test if count is not 0. 
       * @param result The result of the test.
       */
      @Override
      public boolean retry(ITestResult result) {
        boolean retry = false;
    
        if (count.intValue() > 0) {
          retry = retryMethod(result);
          count.decrementAndGet();
        }
        return retry;
      }
    
      /**
       * The method implemented by the class that test if the test
       * must be retried or not.
       * @param result The result of the test.
       * @return true if the test must be retried, false otherwise.
       */
      public abstract boolean retryMethod(ITestResult result);
    }

     

    所以从上面可以看出,如果直接使用继承这个RetryAnalyzerCount 类还是省不少事,直接就可以使用了。

    Class TestListenerAdapter

    IConfigurationListener, IConfigurationListener2, org.testng.internal.IResultListener, org.testng.internal.IResultListener2, ITestListener, ITestNGListener

    上面的是另一个类实现了retry的操作的类。这里不使用。

    我们今天所使用的是IRetryAnalyzer 接口的,代码如下:

        package com.com.baserunner;
        import org.testng.IRetryAnalyzer;
        import org.testng.ITestResult;
        /**
         * @author sumeetmisri@gmail.com
         * @modify alterhu2020@gmail.com
         * @version 1.0
         * @category
         * 
         */
    
        public class RetryFail  implements IRetryAnalyzer
        {
            private final int m_maxRetries = 1;
            private final int m_sleepBetweenRetries = 1000;
            private int currentTry;
            private String previousTest = null;
            private String currentTest = null;
            public RetryFail()
            {
                currentTry = 0;
            }
    
            @Override
            public boolean retry(final ITestResult result)
            {
                // If a testcase has succeeded, this function is not called.        
                boolean retValue = false;        
                
                // Getting the max retries from suite.
               // String maxRetriesStr = result.getTestContext().getCurrentXmlTest().getParameter("maxRetries");
               String maxRetriesStr = result.getTestContext().getSuite().getParameter("maxRetries");
                int maxRetries = m_maxRetries;
                if(maxRetriesStr != null)
                {
                    try        
                    {
                        maxRetries = Integer.parseInt(maxRetriesStr);
                    }
                    catch (final NumberFormatException e)
                    {
                        System.out.println("NumberFormatException while parsing maxRetries from suite file." + e);
                    }
                }
               
                // Getting the sleep between retries from suite.you can from the suite parameter 
                String sleepBetweenRetriesStr = result.getTestContext().getSuite().getParameter("sleepBetweenRetries");
                int sleepBetweenRetries = m_sleepBetweenRetries;
                if(sleepBetweenRetriesStr != null)
                {
                    try        
                    {
                        sleepBetweenRetries = Integer.parseInt(sleepBetweenRetriesStr);
                    }
                    catch (final NumberFormatException e)
                    {
                        System.out.println("NumberFormatException while parsing sleepBetweenRetries from suite file." + e);
                    }
                }
                
                currentTest = result.getTestContext().getCurrentXmlTest().getName();
                
                if (previousTest == null)
                {
                    previousTest = currentTest;
                }
                if(!(previousTest.equals(currentTest)))
                {
                    currentTry = 0;
                }
               
                if (currentTry < maxRetries &&!result.isSuccess())
                {
                    try
                    {
                        Thread.sleep(sleepBetweenRetries);
                    }
                    catch (final InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                    currentTry++;  
                    result.setStatus(ITestResult.SUCCESS_PERCENTAGE_FAILURE);
                    retValue = true;
                              
                }
                else
                {
                    currentTry = 0;
                }
                previousTest = currentTest;
                // if this method returns true, it will rerun the test once again.
                
             
                return retValue;
            }
        }

    还有一个lisetner需要加入到testNG的配置文件中:

    package com.coma.baserunner;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    
    import org.testng.IAnnotationTransformer;
    import org.testng.IRetryAnalyzer;
    import org.testng.annotations.ITestAnnotation;
    
    public class RetryListener implements IAnnotationTransformer {
    
        @SuppressWarnings("rawtypes")
        @Override
        public void transform(ITestAnnotation annotation, Class testClass,
                Constructor testConstructor, Method testMethod) {
    
            IRetryAnalyzer retry = annotation.getRetryAnalyzer();
            if (retry == null) {
                //annotation.setRetryAnalyzer(RetryAnalyzer.class);
                annotation.setRetryAnalyzer(RetryFail.class);
            }
        }
    
    }

    然后在testNG的xml的配置文件中如下配置即可:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
    <suite name="FirstSuite" parallel="false" >
     <!--  <parameter name="configfile" value="/resources/config.properties"></parameter> -->
     <parameter name="excelpath" value="resources/TestData.xls"></parameter>
     <listeners>
       <listener class-name="com.com.baserunner.RetryListener"></listener>
     </listeners> 

     

    以上的配置方法没有任何问题,唯一的缺陷是,运行的时候testNG的报告中会将retry的testcase的次数也计算在内,所以可能造成,运行后的testcase数目不准确,关于这个问题网上也有人在讨论,可是一直都没有得到一个好的接解决。

    最近觉得仔细看看testNG的源代码,看看能不能修改下对应的testNG的报告。使得结果显示的testcase数据与实际的一致,retry的testcase只计算最后一次运行成功的。

    如果有结果,再更新。。。。。。。Smile

  • 相关阅读:
    新概念第二册(1)--英语口语听力课1
    外企面试课程(一)---熟悉常见的缩略词
    公司 邮件 翻译 培训 长难句 结课
    workflow
    公司 邮件 翻译 培训 长难句 20
    公司 邮件 翻译 培训 长难句 19
    Engineering Management
    公司 邮件 翻译 培训 长难句 18
    公司 邮件 翻译 培训 长难句 17
    第14.5节 利用浏览器获取的http信息构造Python网页访问的http请求头
  • 原文地址:https://www.cnblogs.com/alterhu/p/3191701.html
Copyright © 2011-2022 走看看