问题情况                                                 

先说下问题情况,最近在做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);
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

所以从上面可以看出,如果直接使用继承这个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;
}
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }还有一个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);
}
} }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }然后在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>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 



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

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

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

testNG retry 失败的testcase只需要在xml中配置一个listener即可的更多相关文章

  1. Java 在pom.xml中配置build resources, 来防止我们资源导出失败问题(Maven项目)

    在pom.xml中配置build, 来防止我们资源导出失败问题 <!--在build中配置resources, 来防止我们资源导出失败问题--> <build> <res ...

  2. 如何只克隆git仓库中的一个分支?

    git clone -b 例如: git clone -b 指定的分支名字

  3. 思路:当一个表嵌套另一个表时候 只需在dao中引入该mapper即可 进行正常的数据插入 查询 修改等

  4. 解决在web.xml中配置server服务器启动失败问题

    一.问题"Server Tomacat v8.5 Server at locallhost failed to start" 二.解决方法:删除注释@webServlet 三.分析 ...

  5. testng跑失败用例重试

    testng 提高用例通过率,失败用例要重新运行一次 步骤: 1.新建一个Retry 类,implements IRetryAnalyzer接口,这个类里面确定重跑次数,以及分析每次失败是否需要重新运 ...

  6. testng增加失败重跑机制

    注: 以下内容引自 http://www.yeetrack.com/?p=1015 testng增加失败重跑机制 Posted on 2014 年 10 月 31 日 使用Testng框架搭建自动测试 ...

  7. (转)testng对失败时截图处理

    写这篇微博之前,自动化测试代码中有对于失败测试截图的功能,但是却散落在各个catch语句块中.不便于以后的扩展和维护,AOP思想里说明是面向切面编程,把公共的组件提取出来,可以单独修改维护. 但是直到 ...

  8. AGS中通过FeatureServer插入数据失败、插入数据在WMTS请求中无法显示以及version概念的讨论

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 在多个项目中,当我方接口给其他部门人员使用时出现了插入数据失 ...

  9. SQL Server 2008 R2中配置作业失败后邮件发送通知

    SQL Server日常维护中难免会遇到作业失败的情况.失败后自然需要知道它失败了,除了例行检查可以发现出错以外,有一个较实时的监控还是很有必要的.比较专业的监控系统比如SCOM虽然可以监控作业执行情 ...

随机推荐

  1. C# ApartmentState 枚举,指定线程单元状态

    1.ApartmentState 指定的单元状态 Thread. 命名空间:   System.Threading程序集:  mscorlib(位于 mscorlib.dll) 成员       成员 ...

  2. mac或者linux磁力下载方法:远离渣雷

    wget是linux下常用的命令行下载工具,是Linux用户是必不可少的工具,尤其对于网络管理员,经常要下载一些软件. t-get是一个简单的命令行BT下载工具,可以用于BT种子和磁力链接的下载 tg ...

  3. @Autowired注解和静态方法 NoClassDefFoundError could not initialize class 静态类

    NoClassDefFoundError could not initialize class 静态类 spring boot 静态类 java.lang.ExceptionInInitializer ...

  4. anaconda里面安装tensorflow

    这篇文章讲的比较好: https://blog.csdn.net/evaljy/article/details/70209957 用这篇文章的内容,能够安装成功

  5. Unique Binary Search Trees II leetcode java

    题目: Given n, generate all structurally unique BST's (binary search trees) that store values 1...n. F ...

  6. vue-自定义组件传值

    项目中,我们经常会遇到自定义组件传值的问题,方法很多种,但是原理很简单,下述文档总结实际项目中使用的传值方式. 父组件传递给子组件某一值,子组件内会修改该值,然后父组件需要获取新值 ​ 在 Vue 中 ...

  7. SQL Server 2005 Integration Services (SSIS)数据源之MySQL

    一安装MySQL数据库的ODBC驱动 下载MySQL Connector ODBC 3.51.rar 单击setup按默认安装即可! 如下图所示,在ODBC数据源管理器中看到“MySQL ODBC 3 ...

  8. mybatis @Select注解中如何拼写动态sql

    @Mapper public interface DemandCommentMapper extends BaseMapper<DemandComment>{ @Select(" ...

  9. IIS 7.5: HOW TO ENABLE TLS 1.1 AND TLS 1.2

    In IIS 7.5, which is installed on Windows 2008 R2 servers, only SSL 3.0 and TLS 1.0 are enabled for ...

  10. This is a bug I believe, and it took me 2-3 days to figure it out. Please do the following to get it working,

    This is a bug I believe, and it took me 2-3 days to figure it out. Please do the following to get it ...