Riesecuzione della classe completa e non solo @Test in TestNG


9

Sto navigando su StackOverflow da alcuni giorni, cercando di trovare come rieseguire un'intera classe di test e non solo un @Testpasso. Molti dicono che questo non è supportato con TestNG e IRetryAnalyzer, mentre alcuni hanno pubblicato soluzioni alternative, che in realtà non funzionano. Qualcuno è riuscito a farlo? E solo per chiarire le ragioni di ciò, al fine di evitare risposte che affermano che non è supportato nello scopo: TestNG è uno strumento non solo per gli sviluppatori. Significa che viene utilizzato anche dai tester SW per i test e2e. I test E2e possono avere passaggi che dipendono ciascuno dal precedente. Quindi sì, è valido rieseguire l'intera classe di test, piuttosto che semplice @Test, che può essere facilmente eseguita tramite IRetryAnalyzer.

Un esempio di ciò che voglio ottenere sarebbe:

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"));

}

}

Diciamo che testStep_2fallisce, voglio rieseguire class DemoTeste non solotestStep_2


Puoi mostrarci la soluzione alternativa che non funziona?
AndiCover,

Modifica la tua domanda, includi un campione e mostraci quali sono le tue aspettative. Ciò contribuirebbe molto ad aiutare gli altri a darti una risposta che soddisfi le tue aspettative.
Krishnan Mahadevan,

@AndiCover collegamenti a soluzioni alternative che non funzionano (o che sono soluzioni alternative che distruggono la logica TestNG): stackoverflow.com/questions/25781098/... stackoverflow.com/questions/50241880/... stackoverflow.com/questions/53736621/...
gandalf_the_cool

Risposte:


1

Va bene, so che probabilmente vuoi alcune proprietà facili che puoi specificare nella tua @BeforeClass o qualcosa del genere, ma potremmo aver bisogno di aspettare che venga implementato. Almeno non sono riuscito a trovarlo neanche.

Quanto segue è brutto da morire ma penso che faccia il suo lavoro, almeno su piccola scala, resta da vedere come si comporta in scenari più complessi. Forse con più tempo, questo può essere migliorato in qualcosa di meglio.

Ok, quindi ho creato una classe di test simile alla tua:

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.");
        }

    }


Ho la Listenerclasse super solo nel caso in cui vorrei estenderla ad altre classi, ma puoi anche impostare l'ascoltatore nella tua classe di test.

@Listeners(TestListener.class)
public class TestConfig {
   protected static boolean retrySuccessful = false;
   protected static boolean fail = true;
}


Tre dei 4 metodi sopra hanno a RetryAnalyzer. L'ho lasciato testStep_4senza per assicurarmi che quello che sto facendo dopo non rovini il resto dell'esecuzione. Detto RetryAnalyzereffettivamente non riprovare (notare che il metodo restituisce false), ma farà quanto segue:

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;
    }

}


Questo creerà un'esecuzione all'interno della tua esecuzione. Non rovinerà il rapporto e, una volta terminato, continuerà con l'esecuzione principale. Ma "riproverà" i metodi all'interno di quel gruppo.

Sì, lo so, lo so. Ciò significa che eseguirai la tua suite di test per sempre in un ciclo eterno. Ecco perché il RetryAnnotationTransformer. In esso, rimuoveremo RetryAnalyzer dalla seconda esecuzione di quei test:

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);
    }

}


Ora abbiamo l'ultimo dei nostri problemi. La nostra suite di test originale non sa nulla dell'esecuzione "riprova" lì. Questo è dove diventa davvero brutto. Dobbiamo dire al nostro Reporter cosa è appena successo. E questa è la parte che ti incoraggio a migliorare. Mi manca il tempo per fare qualcosa di più bello, ma se posso, lo modificherò ad un certo punto.

Innanzitutto, dobbiamo sapere se l'esecuzione di retryTestNG ha avuto esito positivo. Probabilmente ci sono milioni di modi per farlo meglio, ma per ora funziona. Ho impostato un ascoltatore solo per l'esecuzione di un nuovo tentativo. Puoi vederlo TestRetrysopra, ed è composto da quanto segue:

public class TestListenerRetry extends TestConfig implements ITestListener {

    (...)

    @Override
    public void onFinish(ITestContext context) {
        if (context.getFailedTests().size()==0 && context.getSkippedTests().size()==0) {
            successful = true;
        }
    }

}

Ora il Listener della suite principale, quello che hai visto sopra nella superclasse TestConfigvedrà se la corsa è avvenuta e se è andata bene e aggiornerà il rapporto:

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());
                    }

                }

            }

        }


    }

}

Il rapporto dovrebbe mostrare ora 3 test superati (come sono stati riprovati) e uno che ha fallito perché non faceva parte degli altri 3 test:

Rapporto finale


So che non è quello che stai cercando, ma ti aiuto fino a quando non aggiungono la funzionalità a TestNG.


Spiacenti. Ho dimenticato di aggiungere un condizionale nel Listener principale per aggiornare il rapporto finale solo se la suite Retry è avvenuta e ha avuto esito positivo. Aggiunto ora.
Rodrigo Vaamonde,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.