zoukankan      html  css  js  c++  java
  • testng重试机制

    Testng重试机制

    测试中我们网络突然中断或者其他外界因素,导致本可以执行成功的用例也被记录为失败。所以,我们在自动化脚本中加入了用例失败重试机制,依靠监听用例执行的结果,进行重复执行,并且只会记录一次结果。

    导入依赖

    包含testng和Allurue报告

            <dependency>
                <groupId>org.testng</groupId>
                <artifactId>testng</artifactId>
                <version>6.10</version>
            </dependency>
     <dependency>
                <groupId>io.qameta.allure</groupId>
                <artifactId>allure-testng</artifactId>
                <version>2.13.1</version>
            </dependency>
            
             <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>${aspectj.version}</version>
            </dependency>
    
    
    <properties>
            <allure.version>2.10.0</allure.version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <java.version>1.8</java.version>
            <aspectj.version>1.8.10</aspectj.version>
        </properties>
    
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M1</version>
                <configuration>
                    <!--设置参数命令行 -->
                    <argLine>
                        -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
                    </argLine>
                    <systemPropertyVariables>
                        <!--是否忽略html,解释见下图。与之后在reportNg报告上显示截图相关。当前已经使用allure了,这里可以直接去掉啦 -->
                        <org.uncommons.reportng.escape-output>false</org.uncommons.reportng.escape-output>
                        <!--测试失败后,是否忽略并继续测试 -->
                        <testFailureIgnore>true</testFailureIgnore>
                        <argLine>
                            -Dfile.encoding=UTF-8
                        </argLine>
                        <property>
                            <name>usedefaultlisteners</name>
                            <value>false</value>
                        </property>
                        <property>
                            <name>listener</name>
                            <value>org.uncommons.reportng.HTMLReporter, org.uncommons.reportng.JUnitXMLReporter</value>
                        </property>
                    </systemPropertyVariables>
                    <suiteXmlFiles>
                        <!--代表的是要执行的测试套件名称 -->
                        <suiteXmlFile>test.xml</suiteXmlFile>
                    </suiteXmlFiles>
                    <workingDirectory>target</workingDirectory>
                </configuration>
            </plugin>
        </plugins>
    </build>
    
    设置用例失败重试的次数

    实现IRetryAnalyzer接口的retry方法。

    package com.course.listener;
    
    /**
     * @author : Jack
     * @Description: TODO
     */
    import org.testng.IRetryAnalyzer;
    import org.testng.ITestResult;
    import org.testng.Reporter;
    import org.testng.log4testng.Logger;
    
    public class TestngRetry implements IRetryAnalyzer {
        private static Logger logger = Logger.getLogger(TestngRetry.class);
        private static int maxRetryCount = 3;//最大的重跑次数
        private int retryCount = 1;
    
        @Override
        public boolean retry(ITestResult result) {
            if (retryCount <= maxRetryCount) {
                String message = "Running retry for '" + result.getName()
                        + "' on class " + this.getClass().getName() + " Retrying "
                        + retryCount + " times";
                logger.info(message);
                Reporter.setCurrentTestResult(result);
                Reporter.log("RunCount=" + (retryCount + 1));
                retryCount++;
                return true;
            }
            return false;
        }
    }
    
    
    使用方法一

    在需要重试的方法上加上注解,如下:

    public class TestRetry {
    
        @Test(description = "重试测试",retryAnalyzer = TestngRetry.class)
        public void test01(){
            System.out.println("test01");
            Assert.assertTrue(false,"测试失败");
        }
    
    
        @Test(description = "正常测试")
        public void test02(){
            System.out.println("test02");
            Assert.assertTrue(true,"success");
        }
    
    
    
    }
    
    使用方法二 (更便捷)

    写一个监听类实现IAnnotationTransformer,在xml中或者类加上监听

    package com.course.listener;
    
    /**
     * @author : Jack
     * @Description: TODO
     */
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    import org.testng.IAnnotationTransformer;
    import org.testng.IRetryAnalyzer;
    import org.testng.annotations.ITestAnnotation;
    import org.testng.annotations.Listeners;
    
    public class RetryListener implements IAnnotationTransformer {
    
        @Override
        public void transform(ITestAnnotation annotation,
                              Class testClass, Constructor testConstructor, Method testMethod) {
            IRetryAnalyzer retry = annotation.getRetryAnalyzer();
            if (retry == null) {
                annotation.setRetryAnalyzer(TestngRetry.class);
            }
        }
    
    }
    
    <?xml version="1.0" encoding="UTF-8" ?>
    
    <suite name="test">
        <test name="param">
            <classes>
                <class name="com.course.testng.TestRetry"/>
            </classes>
        </test>
        <listeners>
            <listener class-name="com.course.listener.RetryListener"></listener>
            <listener class-name="com.course.listener.TestngListener"></listener>
    <!--        <listener class-name="org.uncommons.reportng.HTMLReporter"/>-->
    <!--        <listener class-name="org.uncommons.reportng.JUnitXMLReporter"/>-->
        </listeners>
    </suite>
    
    
    解决一条用例执行多次后报告显示重复的问题

    在跑多条用例时,testng会有一个bug:所有用例会公用同一个重试次数。这里需要重写onTestSuccess和onTestFailure接口

    package com.course.listener;
    
    /**
     * @author : Jack
     * @Project: Chapter5
     * @date Date : 2020年07月15日 18:29
     * @Description: TODO
     */
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;
    
    import org.testng.ITestContext;
    import org.testng.ITestResult;
    import org.testng.TestListenerAdapter;
    import org.testng.log4testng.Logger;
    
    /***
    *
    *@Description:所有用例会公用同一个重试次数。这里需要重写onTestSuccess和onTestFailure接口
    *@Author: Jack
    *@Param:
    *@Return:
    *@Date: 2020/9/24 14:07
    **/
    public class TestngListener extends TestListenerAdapter {
        private static Logger logger = Logger.getLogger(TestngListener.class);
        @Override
        public void onFinish(ITestContext testContext) {
            super.onFinish(testContext);
    
            // List of test results which we will delete later
            ArrayList<ITestResult> testsToBeRemoved = new ArrayList<ITestResult>();
            // collect all id's from passed test
            Set<Integer> passedTestIds = new HashSet<Integer>();
            for (ITestResult passedTest : testContext.getPassedTests()
                    .getAllResults()) {
                logger.info("PassedTests = " + passedTest.getName());
                passedTestIds.add(getId(passedTest));
            }
    
            Set<Integer> failedTestIds = new HashSet<Integer>();
            for (ITestResult failedTest : testContext.getFailedTests()
                    .getAllResults()) {
                logger.info("failedTest = " + failedTest.getName());
                int failedTestId = getId(failedTest);
    
                // if we saw this test as a failed test before we mark as to be
                // deleted
                // or delete this failed test if there is at least one passed
                // version
                if (failedTestIds.contains(failedTestId)
                        || passedTestIds.contains(failedTestId)) {
                    testsToBeRemoved.add(failedTest);
                } else {
                    failedTestIds.add(failedTestId);
                }
            }
    
            // finally delete all tests that are marked
            for (Iterator<ITestResult> iterator = testContext.getFailedTests()
                    .getAllResults().iterator(); iterator.hasNext();) {
                ITestResult testResult = iterator.next();
                if (testsToBeRemoved.contains(testResult)) {
                    logger.info("Remove repeat Fail Test: " + testResult.getName());
                    iterator.remove();
                }
            }
    
        }
    
        private int getId(ITestResult result) {
            int id = result.getTestClass().getName().hashCode();
            id = id + result.getMethod().getMethodName().hashCode();
            id = id
                    + (result.getParameters() != null ? Arrays.hashCode(result
                    .getParameters()) : 0);
            return id;
        }
    }
    
    
    

    作者:我是刘先生
    地址:https://www.cnblogs.com/cekaigongchengshi/
    文章转载请标明出处,如果,您认为阅读这篇博客让您有些收获,不妨点击一下推荐按钮,据说喜欢分享的,后来都成了大神

    欢迎扫码关注微信公众号
  • 相关阅读:
    elasticsearch 5.x 系列之七 基于索引别名的零停机升级服务
    Linux 查看系统硬件信息(实例详解)
    linux grep命令详解
    Boot loader: Grub进阶(转)
    Boot loader: Grub入门(转)
    内核模块管理(转)
    Centos启动流程(转)
    Linux 内核启动流程(转)
    程序的运行顺序(转)
    查询进程打开的文件(转)
  • 原文地址:https://www.cnblogs.com/cekaigongchengshi/p/13724787.html
Copyright © 2011-2022 走看看