D'accord, je sais que vous voulez probablement une propriété facile que vous pouvez spécifier dans votre @BeforeClass ou quelque chose comme ça, mais nous devrons peut-être attendre que cela soit implémenté. Au moins, je ne l'ai pas trouvé non plus.
Ce qui suit est moche comme l'enfer mais je pense qu'il fait le travail, au moins à petite échelle, il reste à voir comment il se comporte dans des scénarios plus complexes. Peut-être qu'avec plus de temps, cela peut être amélioré en quelque chose de mieux.
D'accord, j'ai donc créé une classe de test similaire à la vôtre:
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.");
}
}
J'ai le Listener
dans la super classe juste au cas où j'aimerais l'étendre à d'autres classes, mais vous pouvez également définir l'auditeur dans votre classe de test.
@Listeners(TestListener.class)
public class TestConfig {
protected static boolean retrySuccessful = false;
protected static boolean fail = true;
}
Trois des 4 méthodes ci-dessus ont un RetryAnalyzer
. J'ai laissé le testStep_4
sans pour m'assurer que ce que je fais ensuite ne gâche pas le reste de l'exécution. Said RetryAnalyzer
ne réessayera pas réellement (notez que la méthode retourne false
), mais il fera ce qui suit:
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;
}
}
Cela créera une exécution à l'intérieur de votre exécution. Il ne gâchera pas le rapport et, une fois terminé, il continuera avec votre exécution principale. Mais il "réessayera" les méthodes de ce groupe.
Oui, je sais, je sais. Cela signifie que vous allez exécuter votre suite de tests pour toujours dans une boucle éternelle. Voilà pourquoi le RetryAnnotationTransformer
. Dans ce document, nous allons supprimer le RetryAnalyzer de la deuxième exécution de ces 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);
}
}
Nous avons maintenant le dernier de nos problèmes. Notre suite de tests d'origine n'y connaît rien à cette exécution de «nouvelle tentative». C'est là que ça devient vraiment moche. Nous devons dire à notre journaliste ce qui vient de se passer. Et c'est la partie que je vous encourage à améliorer. Je manque de temps pour faire quelque chose de plus agréable, mais si je le peux, je le modifierai à un moment donné.
Tout d'abord, nous devons savoir si l'exécution de retryTestNG a réussi. Il y a probablement un million de façons de faire mieux, mais pour l'instant cela fonctionne. J'ai configuré un écouteur uniquement pour l'exécution de la nouvelle tentative. Vous pouvez le voir ci- TestRetry
dessus, et il se compose des éléments suivants:
public class TestListenerRetry extends TestConfig implements ITestListener {
(...)
@Override
public void onFinish(ITestContext context) {
if (context.getFailedTests().size()==0 && context.getSkippedTests().size()==0) {
successful = true;
}
}
}
Maintenant, l'écouteur de la suite principale, celui que vous avez vu ci-dessus dans la super classe TestConfig
verra si l'exécution s'est déroulée et si cela s'est bien passé et mettra à jour le rapport:
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());
}
}
}
}
}
}
Le rapport devrait montrer maintenant 3 tests réussis (car ils ont été retentés) et un qui a échoué car il ne faisait pas partie des 3 autres tests:
Je sais que ce n'est pas ce que vous recherchez, mais je vous aide à vous servir jusqu'à ce qu'ils ajoutent la fonctionnalité à TestNG.