Führen Sie die vollständige Klasse und nicht nur @Test in TestNG erneut aus

9

Ich habe einige Tage im Stackoverflow gesucht und versucht, eine ganze Testklasse erneut auszuführen, und nicht nur einen @TestSchritt. Viele sagen, dass dies mit TestNG nicht unterstützt wird, und IRetryAnalyzerwährend einige Problemumgehungen veröffentlicht haben, funktionieren diese nicht wirklich. Hat es jemand geschafft? Und nur um die Gründe dafür zu klären, um Antworten zu vermeiden, die besagen, dass dies nicht absichtlich unterstützt wird: TestNG ist ein Tool nicht nur für Entwickler. Dies bedeutet, dass dies auch von SW-Testern für e2e-Tests verwendet wird. E2e-Tests können Schritte enthalten, die jeweils vom vorherigen abhängen. Ja, es ist gültig, die gesamte Testklasse erneut auszuführen, anstatt einfach @Test, was einfach über möglich ist IRetryAnalyzer.

Ein Beispiel für das, was ich erreichen möchte, wäre:

public class DemoTest extends TestBase {

@Test(alwaysRun = true, description = "Do this")
public void testStep_1() {
    driver.navigate().to("http://www.stackoverflow.com");
    Assert.assertEquals(driver.getCurrentUrl().contains("stackoverflow)"));

}

@Test(alwaysRun = true, dependsOnMethods = "testStep_1", description = "Do that")
public void testStep_2() {
    driver.press("button");
    Assert.assertEquals(true, driver.elementIsVisible("button"));

}

@Test(alwaysRun = true, dependsOnMethods = "testStep_2", description = "Do something else")
public void testStep_3() {
   driver.press("button2");
Assert.assertEquals(true, driver.elementIsVisible("button"));

}

}

Nehmen wir an, das testStep_2schlägt fehl, ich möchte es erneut ausführen class DemoTestund nicht nurtestStep_2

gandalf_the_cool
quelle
Können Sie uns die Problemumgehung zeigen, die nicht funktioniert?
AndiCover
Bitte bearbeiten Sie Ihre Frage, fügen Sie ein Beispiel bei und zeigen Sie uns Ihre Erwartungen. Dies würde einen großen Beitrag dazu leisten, anderen zu helfen, eine Antwort zu geben, die Ihren Erwartungen entspricht.
Krishnan Mahadevan
@AndiCover Links zu Problemumgehungen, die nicht funktionieren (oder Problemumgehungen sind, die die testNG-Logik zerstören): stackoverflow.com/questions/25781098/… stackoverflow.com/questions/50241880/… stackoverflow.com/questions/53736621/…
gandalf_the_cool

Antworten:

1

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 Listenerin 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_4ohne gelassen , um sicherzustellen, dass das, was ich als nächstes mache, den Rest der Ausführung nicht beeinträchtigt. Said RetryAnalyzerwird 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 TestRetryoben 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 TestConfighaben, 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:

Abschlussbericht


Ich weiß, dass es nicht das ist, wonach Sie suchen, aber ich helfe Ihnen, bis Sie die Funktionalität zu TestNG hinzufügen.

Rodrigo Vaamonde
quelle
Hoppla ... Ich habe vergessen, im Haupt-Listener eine Bedingung hinzuzufügen, um den Abschlussbericht nur zu aktualisieren, wenn die Wiederholungssuite passiert ist und erfolgreich war. Jetzt hinzugefügt.
Rodrigo Vaamonde