设置: 我有一个扩展IRetryAnalyzer的类,并实现了一个简单的重试逻辑,覆盖了以下方法: public boolean retry(ITestResult result){
我有另一个类,它扩展了类TestListenerAdapter,它重试失败的测试,直到它们通过或报告失败。我已经实现了我的逻辑覆盖以下方法: public void onTestFailure(ITestResult result){
情境: 我总共进行了10次测试。 10次测试中有1次失败2次,并使用我的重试逻辑传递第3次尝试。测试结果显示如下: 总测试:12,失败:2,跳过:0
我想要的是输出正确数量的测试。并且也忽略了自测试结束以来的2次失败。所以结果应该是这样的: 总测试:10,失败:0,跳过:0
我在这里缺少什么?我需要修改ITestResult对象吗?如果是,怎么样?
仅供参考:我能够使用JUnit实现这一点(实现TestRule接口)。
提前致谢。
答案 0 :(得分:6)
请考虑以下测试结果。 2重试:
我所做的是创建一个TestNg监听器,它扩展了默认行为,并在所有测试完成后做了一些魔术。
public class FixRetryListener extends TestListenerAdapter {
@Override
public void onFinish(ITestContext testContext) {
super.onFinish(testContext);
// List of test results which we will delete later
List<ITestResult> testsToBeRemoved = new ArrayList<>();
// collect all id's from passed test
Set <Integer> passedTestIds = new HashSet<>();
for (ITestResult passedTest : testContext.getPassedTests().getAllResults()) {
passedTestIds.add(TestUtil.getId(passedTest));
}
Set <Integer> failedTestIds = new HashSet<>();
for (ITestResult failedTest : testContext.getFailedTests().getAllResults()) {
// id = class + method + dataprovider
int failedTestId = TestUtil.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)) {
iterator.remove();
}
}
}
}
基本上我做了两件事:
要识别testresult,我使用以下简单的哈希函数:
public class TestUtil {
public static int getId(ITestResult result) {
int id = result.getTestClass().getName().hashCode();
id = 31 * id + result.getMethod().getMethodName().hashCode();
id = 31 * id + (result.getParameters() != null ? Arrays.hashCode(result.getParameters()) : 0);
return id;
}
}
这种方法也适用于数据提供者,但有一个小的限制!如果您使用具有随机值的数据提供程序,则会遇到问题:
@DataProvider(name = "dataprovider")
public Object[][] getData() {
return new Object[][]{{System.currentTimeMillis()}};
}
对于失败的测试,重新评估数据提供者。因此,您将获得一个新的时间戳,同一个mehod的result1和result2将导致不同的哈希值。解决方案是在getId()方法中包含parameterIndex而不是参数,但似乎这样的值不包含在ITestResult中。
将此简单示例视为概念证明:
@Listeners(value = FixRetryListener.class)
public class SimpleTest {
private int count = 0;
@DataProvider(name = "dataprovider")
public Object[][] getData() {
return new Object[][]{{"Run1"},{"Run2"}};
}
@Test(retryAnalyzer = RetryAnalyzer.class, dataProvider = "dataprovider")
public void teste(String testName) {
count++;
System.out.println("---------------------------------------");
System.out.println(testName + " " + count);
if (count % 3 != 0) {
Assert.fail();
}
count = 0;
}
}
将屈服于:
Total tests run: 2, Failures: 0, Skips: 0
答案 1 :(得分:2)
我尝试过,尝试过并尝试过。 但现在终于有效了
<强> MyRetryAnalyzer.java 强>
import org.testng.IRetryAnalyzer;
import org.testng.ITestResult;
import java.util.concurrent.atomic.AtomicInteger;
public class MyRetryAnalyzer implements IRetryAnalyzer {
private static int MAX_RETRY_COUNT = 3;
AtomicInteger count = new AtomicInteger(MAX_RETRY_COUNT);
public boolean isRetryAvailable() {
return (count.intValue() > 0);
}
@Override
public boolean retry(ITestResult result) {
boolean retry = false;
if (isRetryAvailable()) {
System.out.println("Going to retry test case: " + result.getMethod() + ", " + (MAX_RETRY_COUNT - count.intValue() + 1) + " out of " + MAX_RETRY_COUNT);
retry = true;
count.decrementAndGet();
}
return retry;
}
}
<强> MyTestListenerAdapter.java 强>
import org.testng.*;
import java.util.*;
public class MyTestListenerAdapter extends TestListenerAdapter {
@Override
public void onTestFailure(ITestResult result) {
if (result.getMethod().getRetryAnalyzer() != null) {
MyRetryAnalyzer retryAnalyzer = (MyRetryAnalyzer)result.getMethod().getRetryAnalyzer();
if(retryAnalyzer.isRetryAvailable()) {
} else {
result.setStatus(ITestResult.FAILURE);
}
Reporter.setCurrentTestResult(result);
}
}
@Override
public void onFinish(ITestContext context) {
Iterator<ITestResult> failedTestCases =context.getFailedTests().getAllResults().iterator();
while (failedTestCases.hasNext()) {
System.out.println("failedTestCases");
ITestResult failedTestCase = failedTestCases.next();
ITestNGMethod method = failedTestCase.getMethod();
if (context.getFailedTests().getResults(method).size() > 1) {
System.out.println("failed test case remove as dup:" + failedTestCase.getTestClass().toString());
failedTestCases.remove();
} else {
if (context.getPassedTests().getResults(method).size() > 0) {
System.out.println("failed test case remove as pass retry:" + failedTestCase.getTestClass().toString());
failedTestCases.remove();
}
}
}
}
}
您测试课程
@Listeners(value = MyTestListenerAdapter.class)
public class Test {
//Your data provider
@DataProvider
@Test(retryAnalyzer = MyRetryAnalyzer.class)
public void testMethod () {
//your code goes here
}
}
答案 2 :(得分:1)
我的方法建立在Morvader's answer之上,但增加了定义重试分析器的能力,即使在重试之后方法已经过去,也会遵循实际失败测试的原始意图。
我也没有发现需要倾向于onFinish()方法中的测试次数,这些数字在 maven-surefire-plugin version 2.18 中显得很好
<强> RetryListenerAdapter 强>
public class RetryListenerAdapter extends TestListenerAdapter {
@Override
public void onTestFailure(ITestResult tr) {
IRetryAnalyzer retryAnalyzer = tr.getMethod().getRetryAnalyzer();
if (retryAnalyzer == null || !(retryAnalyzer instanceof IRetryAnalyzerWithSkip)) {
super.onTestFailure(tr);
} else if (((IRetryAnalyzerWithSkip) retryAnalyzer).isRetryable()) {
tr.setStatus(ITestResult.SKIP);
super.onTestSkipped(tr);
} else {
super.onTestFailure(tr);
}
}
}
<强> IRetryAnalyzerWithSkip 强>
public interface IRetryAnalyzerWithSkip extends IRetryAnalyzer {
boolean isRetryable();
}
<强>重试强>
public class Retry implements IRetryAnalyzerWithSkip {
private int retryCount = 0;
private int maxRetryCount = 3;
public boolean retry(ITestResult result) {
if (retryCount < maxRetryCount) {
retryCount++;
return true;
}
return false;
}
@Override
public boolean isRetryable() {
return retryCount < maxRetryCount;
}
}
答案 3 :(得分:0)
我使用这种方法:
<强> ListenerApadter 强>:
public class MyTestListenerAdapter extends TestListenerAdapter {
@Override
public void onTestFailure(ITestResult result) {
if (result.getMethod().getRetryAnalyzer() != null) {
MyRetryAnalyzer retryAnalyzer = (MyRetryAnalyzer)result.getMethod().getRetryAnalyzer();
if(retryAnalyzer.isRetryAvailable()) {
result.setStatus(ITestResult.SKIP);
} else {
result.setStatus(ITestResult.FAILURE);
}
Reporter.setCurrentTestResult(result);
}
}
@Overrride
public void onFinish(ITestContext context) {
Iterator<ITestResult> failedTestCases =context.getFailedTests().getAllResults().iterator();
while (failedTestCases.hasNext()) {
System.out.println("failedTestCases");
ITestResult failedTestCase = failedTestCases.next();
ITestNGMethod method = failedTestCase.getMethod();
if (context.getFailedTests().getResults(method).size() > 1) {
System.out.println("failed test case remove as dup:" + failedTestCase.getTestClass().toString());
failedTestCases.remove();
} else {
if (context.getPassedTests().getResults(method).size() > 0) {
System.out.println("failed test case remove as pass retry:" + failedTestCase.getTestClass().toString());
failedTestCases.remove();
}
}
}
}
}
<强> RetryAnalizer 强>:
public class MyRetryAnalyzer implements IRetryAnalyzer {
private static int MAX_RETRY_COUNT = 3;
AtomicInteger count = new AtomicInteger(MAX_RETRY_COUNT);
public boolean isRetryAvailable() {
return (count.intValue() > 0);
}
@Override
public boolean retry(ITestResult result) {
boolean retry = false;
if (isRetryAvailable()) {
System.out.println("Going to retry test case: " + result.getMethod() + ", " + (MAX_RETRY_COUNT - count.intValue() + 1) + " out of " + MAX_RETRY_COUNT);
retry = true;
count.decrementAndGet();
}
return retry;
}
}
POM.xml - &gt; Surefire配置:
这是您应该配置&#34;覆盖&#34; surefire听众有自己的柜台。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<suiteXmlFiles><suiteXmlFile>${basedir}/testng.xml</suiteXmlFile></suiteXmlFiles>
<properties>
<property>
<name>listener</name>
<value>Utils.MyTestListenerAdapter,Utils.MyRetryAnalizer</value>
</property>
</properties>
答案 4 :(得分:0)
此问题已解决,无需在最新版本的TestNG 7.1.0中的Retry Analyzer中进行任何额外的处理。
现在,已重试的测试将被标记为“重试”,您可以在
运行后生成的emailable-report.html
个报告。
如果您仍想在重试测试时进行一些逻辑处理,则可以执行以下操作:
@AfterMethod(alwaysRun = true)
public void afterMethod( ITestResult result) throws Exception {
if (result.wasRetried()){
//your logic here
}