首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TestNG重试失败的测试不能输出正确的测试结果

TestNG重试失败的测试不能输出正确的测试结果
EN

Stack Overflow用户
提问于 2012-10-30 02:36:06
回答 4查看 12.3K关注 0票数 14

安装程序:I有一个类,它扩展了IRetryAnalyzer,并实现了一个简单的重试逻辑,覆盖了以下方法:公共布尔重试(ITestResult结果){

我还有一个类扩展了类TestListenerAdapter,它会重试失败的测试,直到它们通过或报告失败为止。我实现了重写以下方法的逻辑: public void onTestFailure(ITestResult结果){

场景:共有10个测试。10次测试中有1次失败2次,第三次尝试用我的重试逻辑通过。测试结果显示:总测试: 12,失败: 2,跳过:0

我想要的是输出正确的运行测试数量。同时也忽略了测试结束后的2次失败。因此,结果应该如下所示:总测试: 10,失败:0,跳过:0

我在这里错过了什么?我需要修改ITestResult对象吗?如果是,怎么做?

FYI:我能够使用JUnit (实现TestRule接口)实现这一点。

提前谢谢。

EN

回答 4

Stack Overflow用户

发布于 2013-08-22 07:55:47

请考虑下面的测试结果与最大值。2次复审:

  1. 通过了=>总体上没问题!
  2. 失败了,通过了=>总体上没问题!
  3. 失败了,失败了,通过了=>总体上没问题!
  4. 失败,失败,失败=>整体失败!

我所做的是创建一个TestNg侦听器,它扩展了默认行为,并在所有测试完成后做了一些神奇的工作。

代码语言:javascript
复制
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();
            }
        }

    }

}

基本上我做了两件事:

  1. 收集所有通过的测试。如果遇到至少一次通过测试的失败测试,我将删除失败的测试(这将涵盖上述案例2和3)。
  2. 迭代所有失败的测试。如果遇到以前失败的测试,则删除当前失败的结果。(这实际上包括案件3和4)。这也意味着我只会保留第一个失败的结果,如果有几个失败的结果。

要标识测试结果,我使用以下简单的散列函数:

代码语言:javascript
复制
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;
    }
}

这种方法也适用于数据提供者,但是有一个小的限制!如果使用具有随机值的数据提供程序,则会遇到以下问题:

代码语言:javascript
复制
@DataProvider(name = "dataprovider")
public Object[][] getData() {
    return new Object[][]{{System.currentTimeMillis()}};
}

对于失败的测试,将重新评估数据提供程序。因此,您将得到一个新的时间戳,相同方法的result1和result2将导致不同的哈希值。解决方案是将parameterIndex包含在getId()方法中,而不是参数中,但是这样的值似乎没有包含在ITestResult中。

将这个简单的例子作为概念的证明:

代码语言:javascript
复制
@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;
    }

}

将屈服于:

代码语言:javascript
复制
Total tests run: 2, Failures: 0, Skips: 0
票数 6
EN

Stack Overflow用户

发布于 2016-02-17 16:19:33

我试过,试过,试过。但现在终于起作用了

MyRetryAnalyzer.java

代码语言:javascript
复制
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

代码语言:javascript
复制
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();
                }
            }
        }
    }
}

您测试类

代码语言:javascript
复制
@Listeners(value = MyTestListenerAdapter.class)

public class Test  {

//Your data provider
@DataProvider

@Test(retryAnalyzer = MyRetryAnalyzer.class)
public void testMethod () {
    //your code goes here
 }

}
票数 2
EN

Stack Overflow用户

发布于 2015-03-18 16:21:37

我采用这种方法:

ListenerApadter

代码语言:javascript
复制
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

代码语言:javascript
复制
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 ->系统配置:

这就是你应该配置“覆盖”的必胜客侦听器有他们自己的计数器。

代码语言:javascript
复制
<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>
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13131912

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档