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 Listener
classe 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_4
senza per assicurarmi che quello che sto facendo dopo non rovini il resto dell'esecuzione. Detto RetryAnalyzer
effettivamente 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 TestRetry
sopra, 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 TestConfig
vedrà 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:

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