Гаразд, я знаю, що ви, мабуть, хочете, щоб було легке властивість, яке ви можете вказати у своєму @BeforeClass або щось подібне, але нам, можливо, доведеться чекати, коли це буде здійснено. Принаймні, я теж не міг його знайти.
Далі це некрасиво, як пекло, але я думаю, що це робить роботу, принаймні в невеликих масштабах, залишається побачити, як він поводиться в більш складних сценаріях. Можливо, за допомогою більшого часу це можна вдосконалити в щось краще.
Гаразд, тому я створив тестовий клас, подібний до вашого:
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.");
}
}
У мене є Listener
супер клас на той випадок, якщо я хотів би поширити це на інші класи, але ви також можете встановити слухача у вашому тестовому класі.
@Listeners(TestListener.class)
public class TestConfig {
protected static boolean retrySuccessful = false;
protected static boolean fail = true;
}
Три з 4 вище способів мають RetryAnalyzer
. Я залишив це testStep_4
без цього, щоб переконатися, що те, що я роблю далі, не псується з рештою страти. Саїд RetryAnalyzer
насправді не намагатиметься повторити (зауважте, що метод повертається false
), але він зробить наступне:
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;
}
}
Це створить виконання всередині вашого виконання. Він не зіпсується із звітом, і як тільки він закінчиться, він продовжить основне виконання. Але це "повторить" методи всередині цієї групи.
Так, я знаю, я знаю. Це означає, що ви вічно будете виконувати свій тестовий набір у вічному циклі. Ось чому RetryAnnotationTransformer
. У ньому ми видалимо RetryAnalyzer з другого виконання цих тестів:
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);
}
}
Зараз у нас є останні з наших проблем. Наш оригінальний тестовий набір нічого не знає про те "повторне" виконання там. Тут стає по-справжньому потворно. Нам потрібно розповісти нашому Репортеру, що саме сталося. І це та частина, яку я заохочую вас до вдосконалення. Мені не вистачає часу, щоб зробити щось приємніше, але якщо я можу, я відредагую це в якийсь момент.
По-перше, ми повинні знати, чи успішно було виконано retryTestNG. Напевно, є мільйон способів зробити це краще, але наразі це працює. Я налаштував слухача саме для повторного виконання. Ви можете побачити його TestRetry
вище, і він складається з наступного:
public class TestListenerRetry extends TestConfig implements ITestListener {
(...)
@Override
public void onFinish(ITestContext context) {
if (context.getFailedTests().size()==0 && context.getSkippedTests().size()==0) {
successful = true;
}
}
}
Тепер слухач основного набору, той, якого ви бачили вище в суперкласі TestConfig
, побачить, чи відбувся запуск і чи пішов він добре, і оновить звіт:
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());
}
}
}
}
}
}
У звіті мають бути показані 3 пройдені тести (як вони були повторно), і один, який не вдався, оскільки він не був частиною інших 3 тестів:
Я знаю, що це не те, що ви шукаєте, але я допомагаю йому служити вам, поки вони не додадуть функціональності для TestNG.