Хорошо, я знаю, что вам, вероятно, нужно какое-то простое свойство, которое вы можете указать в своем @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.