热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

testNGretry失败的testcase只需要在xml中配置一个listener即可

问题情况先说下问题情况,最近在做testNG与selenium集成做自动化测试的问题。因为如果将testNG做UI测试的话,很多情况下可能测试是失败的&

问题情况                                                 

先说下问题情况,最近在做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();}@Testpublic void demoTest2(){DemoPage dp2=new DemoPage();dp2.demoTest2();}
}

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.
*/@Overridepublic 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;}@Overridepublic 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 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")@Overridepublic 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&#61;"FirstSuite" parallel&#61;"false" ><parameter name&#61;"excelpath" value&#61;"resources/TestData.xls">parameter><listeners><listener class-name&#61;"com.com.baserunner.RetryListener">listener>listeners>

 

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

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

如果有结果&#xff0c;再更新。。。。。。。Smile

转:https://www.cnblogs.com/alterhu/p/3191701.html



推荐阅读
  • Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 本文详细介绍了Java中org.w3c.dom.Text类的splitText()方法,通过多个代码示例展示了其实际应用。该方法用于将文本节点在指定位置拆分为两个节点,并保持在文档树中。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 本文探讨了如何优化和正确配置Kafka Streams应用程序以确保准确的状态存储查询。通过调整配置参数和代码逻辑,可以有效解决数据不一致的问题。 ... [详细]
  • 本文介绍如何使用阿里云的fastjson库解析包含时间戳、IP地址和参数等信息的JSON格式文本,并进行数据处理和保存。 ... [详细]
  • 本题通过将每个矩形视为一个节点,根据其相对位置构建拓扑图,并利用深度优先搜索(DFS)或状态压缩动态规划(DP)求解最小涂色次数。本文详细解析了该问题的建模思路与算法实现。 ... [详细]
  • 深入解析 Spring Security 用户认证机制
    本文将详细介绍 Spring Security 中用户登录认证的核心流程,重点分析 AbstractAuthenticationProcessingFilter 和 AuthenticationManager 的工作原理。通过理解这些组件的实现,读者可以更好地掌握 Spring Security 的认证机制。 ... [详细]
  • 本文介绍如何在Linux Mint系统上搭建Rust开发环境,包括安装IntelliJ IDEA、Rust工具链及必要的插件。通过详细步骤,帮助开发者快速上手。 ... [详细]
  • 本文详细介绍了 Flink 和 YARN 的交互机制。YARN 是 Hadoop 生态系统中的资源管理组件,类似于 Spark on YARN 的配置方式。我们将基于官方文档,深入探讨如何在 YARN 上部署和运行 Flink 任务。 ... [详细]
  • golang常用库:配置文件解析库/管理工具viper使用
    golang常用库:配置文件解析库管理工具-viper使用-一、viper简介viper配置管理解析库,是由大神SteveFrancia开发,他在google领导着golang的 ... [详细]
  • 本文介绍如何在 Android 中通过代码模拟用户的点击和滑动操作,包括参数说明、事件生成及处理逻辑。详细解析了视图(View)对象、坐标偏移量以及不同类型的滑动方式。 ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
  • 在 Flutter 开发过程中,开发者经常会遇到 Widget 构造函数中的可选参数 Key。对于初学者来说,理解 Key 的作用和使用场景可能是一个挑战。本文将详细探讨 Key 的概念及其应用场景,并通过实例帮助你更好地掌握这一重要工具。 ... [详细]
  • 本文详细介绍了如何准备和安装 Eclipse 开发环境及其相关插件,包括 JDK、Tomcat、Struts 等组件的安装步骤及配置方法。 ... [详细]
author-avatar
执信电影频道
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有