Okay, ich weiß, dass Sie wahrscheinlich eine einfache Eigenschaft wünschen, die Sie in Ihrer @BeforeClass oder ähnlichem angeben können, aber wir müssen möglicherweise warten, bis diese implementiert ist. Zumindest konnte ich es auch nicht finden.
Das Folgende ist höllisch hässlich, aber ich denke, es macht den Job, zumindest in kleinem Maßstab. Es bleibt abzuwarten, wie es sich in komplexeren Szenarien verhält. Vielleicht kann dies mit der Zeit zu etwas Besserem verbessert werden.
Okay, also habe ich eine Testklasse erstellt, die Ihrer ähnlich ist:
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.");
}
}
Ich habe die Listener
in der Superklasse nur für den Fall, dass ich dies auf andere Klassen ausweiten möchte, aber Sie können den Listener auch in Ihrer Testklasse einstellen.
@Listeners(TestListener.class)
public class TestConfig {
protected static boolean retrySuccessful = false;
protected static boolean fail = true;
}
Drei der 4 oben genannten Methoden haben a RetryAnalyzer
. Ich habe das testStep_4
ohne gelassen , um sicherzustellen, dass das, was ich als nächstes mache, den Rest der Ausführung nicht beeinträchtigt. Said RetryAnalyzer
wird nicht wirklich Wiederholungs (beachten Sie, dass die Methode zurückgibt false
), aber es wird folgendes tun:
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;
}
}
Dadurch wird eine Ausführung innerhalb Ihrer Ausführung erstellt. Der Bericht wird nicht durcheinander gebracht, und sobald er fertig ist, wird Ihre Hauptausführung fortgesetzt. Aber es wird die Methoden innerhalb dieser Gruppe "wiederholen".
Ja, ich weiß, ich weiß. Dies bedeutet, dass Sie Ihre Testsuite für immer in einer ewigen Schleife ausführen werden. Deshalb die RetryAnnotationTransformer
. Darin entfernen wir den RetryAnalyzer aus der zweiten Ausführung dieser Tests:
public class RetryAnnotationTransformer extends TestConfig implements IAnnotationTransformer {
@SuppressWarnings("rawtypes")
@Override
public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
fail = false; // This is just for debugging. Will make testStep_2 pass in the second run.
annotation.setRetryAnalyzer(null);
}
}
Jetzt haben wir das letzte unserer Probleme. Unsere ursprüngliche Testsuite weiß nichts über diese "Wiederholungsausführung" dort. Hier wird es wirklich hässlich. Wir müssen unserem Reporter erzählen, was gerade passiert ist. Und das ist der Teil, den ich Sie ermutige, sich zu verbessern. Mir fehlt die Zeit, um etwas Schöneres zu tun, aber wenn ich kann, werde ich es irgendwann bearbeiten.
Zunächst müssen wir wissen, ob die Ausführung von retryTestNG erfolgreich war. Es gibt wahrscheinlich eine Million Möglichkeiten, dies besser zu machen, aber im Moment funktioniert dies. Ich habe einen Listener nur für die Wiederholung der Ausführung eingerichtet. Sie können es TestRetry
oben sehen und es besteht aus folgenden Elementen:
public class TestListenerRetry extends TestConfig implements ITestListener {
(...)
@Override
public void onFinish(ITestContext context) {
if (context.getFailedTests().size()==0 && context.getSkippedTests().size()==0) {
successful = true;
}
}
}
Jetzt wird der Listener der Hauptsuite, den Sie oben in der Superklasse gesehen TestConfig
haben, sehen, ob der Lauf stattgefunden hat und ob er gut gelaufen ist, und den Bericht aktualisieren:
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());
}
}
}
}
}
}
Der Bericht sollte nun 3 bestandene Tests (da sie wiederholt wurden) und einen fehlgeschlagenen Test anzeigen, da er nicht Teil der anderen 3 Tests war:
Ich weiß, dass es nicht das ist, wonach Sie suchen, aber ich helfe Ihnen, bis Sie die Funktionalität zu TestNG hinzufügen.