Si prega di considerare i seguenti risultati del test con max. 2 tentativi:
- superato => nel complesso ok!
- Fallito, superato => Nel complesso ok!
- Failed, Failed, Passed => Nel complesso ok!
- Failed, Failed, Failed => Errore generale!
Quello che ho fatto è creare un listener TestNg che estenda il comportamento predefinito e faccia un po 'di magia dopo che tutti i test sono terminati.
public class FixRetryListener extends TestListenerAdapter {
@Override
public void onFinish(ITestContext testContext) {
super.onFinish(testContext);
// List of test results which we will delete later
List<ITestResult> testsToBeRemoved = new ArrayList<>();
// collect all id's from passed test
Set <Integer> passedTestIds = new HashSet<>();
for (ITestResult passedTest : testContext.getPassedTests().getAllResults()) {
passedTestIds.add(TestUtil.getId(passedTest));
}
Set <Integer> failedTestIds = new HashSet<>();
for (ITestResult failedTest : testContext.getFailedTests().getAllResults()) {
// id = class + method + dataprovider
int failedTestId = TestUtil.getId(failedTest);
// if we saw this test as a failed test before we mark as to be deleted
// or delete this failed test if there is at least one passed version
if (failedTestIds.contains(failedTestId) || passedTestIds.contains(failedTestId)) {
testsToBeRemoved.add(failedTest);
} else {
failedTestIds.add(failedTestId);
}
}
// finally delete all tests that are marked
for (Iterator<ITestResult> iterator = testContext.getFailedTests().getAllResults().iterator(); iterator.hasNext();) {
ITestResult testResult = iterator.next();
if (testsToBeRemoved.contains(testResult)) {
iterator.remove();
}
}
}
}
Fondamentalmente io fare 2 cose:
- raccogliere tutti i test è stato superato. Se incontro un test fallito con almeno un test superato, rimuovo il test fallito (che copre i casi 2 e 3 dall'alto)
- Iterate su tutti i test non riusciti. Se incontro un test fallito che in precedenza non riuscivo, rimuovo il risultato corrente non riuscito. (Ciò riguarderebbe effettivamente il caso 3 e 4). Ciò significa anche che manterrò il primo risultato fallito solo se ci sono molti risultati falliti.
Per identificare un TestResult io uso il seguente semplice funzione hash:
public class TestUtil {
public static int getId(ITestResult result) {
int id = result.getTestClass().getName().hashCode();
id = 31 * id + result.getMethod().getMethodName().hashCode();
id = 31 * id + (result.getParameters() != null ? Arrays.hashCode(result.getParameters()) : 0);
return id;
}
}
Questo approccio funziona con dataproviders pure ma ha una piccola limitazione!Se si utilizza dataproviders con valori casuali si incorrerà in problemi:
@DataProvider(name = "dataprovider")
public Object[][] getData() {
return new Object[][]{{System.currentTimeMillis()}};
}
Per i test falliti il dataprovider si rivaluta. Pertanto otterrai un nuovo timestamp e il risultato1 e il risultato2 per lo stesso metodo genereranno diversi valori hash. La soluzione sarebbe includere il parametroIndex nel metodo getId() invece dei parametri, ma sembra che tale valore non sia incluso in ITestResult.
Vedere questo semplice esempio, come prova di concetto:
@Listeners(value = FixRetryListener.class)
public class SimpleTest {
private int count = 0;
@DataProvider(name = "dataprovider")
public Object[][] getData() {
return new Object[][]{{"Run1"},{"Run2"}};
}
@Test(retryAnalyzer = RetryAnalyzer.class, dataProvider = "dataprovider")
public void teste(String testName) {
count++;
System.out.println("---------------------------------------");
System.out.println(testName + " " + count);
if (count % 3 != 0) {
Assert.fail();
}
count = 0;
}
}
produrrà in:
Total tests run: 2, Failures: 0, Skips: 0
Avete trovato una soluzione a questo ancora? Grazie. – derrdji
Purtroppo no. Vivere con il problema per ora. –