好的,我知道你可能希望在@BeforeClass中指定一些简单的属性之类的东西,但是我们可能需要等待实现。至少我也找不到它。
以下方法非常丑陋,但我认为它能够胜任工作,至少在小范围内,还需要观察其在更复杂的情况下的表现。也许随着时间的推移,这个方法可以改进成为更好的东西。
好的,所以我创建了一个类似于你的测试类:
public class RetryTest extends TestConfig {
public class RetryTest extends TestConfig {
Assertion assertion = new Assertion();
@Test( enabled = true,
groups = { "retryTest" },
retryAnalyzer = TestRetry.class,
ignoreMissingDependencies = false)
public void testStep_1() {
}
@Test( enabled = true,
groups = { "retryTest" },
retryAnalyzer = TestRetry.class,
dependsOnMethods = "testStep_1",
ignoreMissingDependencies = false)
public void testStep_2() {
if (fail) assertion.fail("This will fail the first time and not the second.");
}
@Test( enabled = true,
groups = { "retryTest" },
retryAnalyzer = TestRetry.class,
dependsOnMethods = "testStep_2",
ignoreMissingDependencies = false)
public void testStep_3() {
}
@Test( enabled = true)
public void testStep_4() {
assertion.fail("This should leave a failure in the end.");
}
}
我在超类中放置了Listener
,以便将来可以扩展到其他类中,但是你也可以在测试类中设置监听器。
@Listeners(TestListener.class)
public class TestConfig {
protected static boolean retrySuccessful = false;
protected static boolean fail = true;
}
以上4种方法中有3种带有RetryAnalyzer
。我故意将testStep_4
留下没有加上它,以确保接下来要做的事情不会影响其余的执行。所述的RetryAnalyzer
实际上不会重试(请注意该方法返回false
),但它会执行以下操作:
public class TestRetry implements IRetryAnalyzer {
public static TestNG retryTestNG = null;
@Override
public boolean retry(ITestResult result) {
Class[] classes = {CreateBookingTest.class};
TestNG retryTestNG = new TestNG();
retryTestNG.setDefaultTestName("RETRY TEST");
retryTestNG.setTestClasses(classes);
retryTestNG.setGroups("retryTest");
retryTestNG.addListener(new RetryAnnotationTransformer());
retryTestNG.addListener(new TestListenerRetry());
retryTestNG.run();
return false;
}
}
这将在您的执行内部创建一个执行。它不会干扰报告,并且一旦完成,它将继续您的主要执行。但是它将“重试”该组中的方法。
是的,我知道,这意味着您将永远在无限循环中执行测试套件。这就是为什么需要
RetryAnnotationTransformer
。在其中,我们将从这些测试的第二次执行中删除RetryAnalyzer:
public class RetryAnnotationTransformer extends TestConfig implements IAnnotationTransformer {
@SuppressWarnings("rawtypes")
@Override
public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
fail = false;
annotation.setRetryAnalyzer(null);
}
}
现在我们面临最后一个问题。我们的原始测试套件对“重试”执行一无所知。这就是问题的关键。我们需要告诉我们的报告生成器发生了什么。这是我鼓励您改进的部分。我没有时间做得更好,但如果可以的话,我会在某个时候进行编辑。
首先,我们需要知道retryTestNG执行是否成功。可能有一百万种更好的方法来做到这一点,但目前为止这样做就可以了。我为重试执行设置了一个监听器。您可以在上面的中看到它,它由以下内容组成:
public class TestListenerRetry extends TestConfig implements ITestListener {
(...)
@Override
public void onFinish(ITestContext context) {
if (context.getFailedTests().size()==0 && context.getSkippedTests().size()==0) {
successful = true;
}
}
}
现在,主套件的监听器(即您在超类TestConfig中看到的那个)将检查运行是否发生以及是否顺利,并更新报告:
public class TestListener extends TestConfig implements ITestListener , ISuiteListener {
(...)
@Override
public void onFinish(ISuite suite) {
if (TestRetry.retryTestNG != null) {
for (ITestNGMethod iTestNGMethod : suite.getMethodsByGroups().get("retryTest")) {
Collection<ISuiteResult> iSuiteResultList = suite.getResults().values();
for (ISuiteResult iSuiteResult : iSuiteResultList) {
ITestContext iTestContext = iSuiteResult.getTestContext();
List<ITestResult> unsuccessfulMethods = new ArrayList<ITestResult>();
for (ITestResult iTestResult : iTestContext.getFailedTests().getAllResults()) {
if (iTestResult.getMethod().equals(iTestNGMethod)) {
iTestContext.getFailedTests().removeResult(iTestResult);
unsuccessfulMethods.add(iTestResult);
}
}
for (ITestResult iTestResult : iTestContext.getSkippedTests().getAllResults()) {
if (iTestResult.getMethod().equals(iTestNGMethod)) {
iTestContext.getSkippedTests().removeResult(iTestResult);
unsuccessfulMethods.add(iTestResult);
}
}
for (ITestResult iTestResult : unsuccessfulMethods) {
iTestResult.setStatus(1);
iTestContext.getPassedTests().addResult(iTestResult, iTestResult.getMethod());
}
}
}
}
}
}
报告现在应该显示通过了3个测试(因为它们被重试了),还有一个失败的测试,因为它不是其他3个测试的一部分。
![Final report](https://istack.dev59.com/dvyUg.webp)
我知道这不是你要找的,但在TestNG添加该功能之前,我希望它能对你有所帮助。