请考虑以下最大测试结果。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();
}
}
}
}
基本上我做两件事:
- 收集所有通过的测试。如果我遇到至少一个通过测试的失败测试,我会删除失败的测试(这将涵盖上面的案例 2 和 3)
- 遍历所有失败的测试。如果我遇到以前失败的失败测试,我会删除当前失败的结果。(这实际上涵盖了案例 3 和 4)。这也意味着如果有几个失败的结果,我只会保留第一个失败的结果。
为了识别测试结果,我使用以下简单的哈希函数:
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()}};
}
对于失败的测试,将重新评估数据提供者。因此,您将获得一个新的时间戳,并且相同方法的 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