JUnit5: как повторить неудачный тест?
одна из практики, которой следуют многие компании, - повторять нестабильный тест, пока не пройдет x раза (подряд или в общей сложности). Если он выполняется n раз и не пройти по крайней мере x раз он отмечен как неудачный.
TestNG поддерживает это со следующей аннотацией:
@Test(invocationCount = 5, successPercentage = 40)
Как я могу реализовать аналогичную функциональность с JUnit5?
в JUnit5 есть аналогичная аннотация, называемая @RepeatedTest(5)
но это не выполняется условно.
3 ответов
хорошо, я взял немного времени, чтобы собрать небольшой пример того, как это сделать с помощью TestTemplateInvocationContextProvider
, ExecutionCondition
и TestExecutionExceptionHandler
точки расширения.
способ, которым я смог справиться с неудачными тестами, состоял в том, чтобы пометить их как "прерванные", а не позволить им потерпеть неудачу (так что все выполнение теста не считает это неудачей) и только неудачные тесты, когда мы не можем получить минимальное количество успешных запусков. Если минимум количество тестов уже удалось, затем мы также отмечаем оставшиеся тесты как "отключенные". Ошибки теста отслеживаются в ExtensionContext.Store
так, что государство можно посмотреть вверх на каждом месте.
это очень грубый пример, который определенно имеет несколько проблем, но, надеюсь, может служить примером того, как составлять различные аннотации. Кончилось тем, что я написал его в Котлине:--30-->
@Retry
-аннотация esque свободно основана на TestNG пример:
import org.junit.jupiter.api.TestTemplate
import org.junit.jupiter.api.extension.ExtendWith
@TestTemplate
@Target(AnnotationTarget.FUNCTION)
@ExtendWith(RetryTestExtension::class)
annotation class Retry(val invocationCount: Int, val minSuccess: Int)
TestTemplateInvocationContext
используется templatized тесты:
import org.junit.jupiter.api.extension.Extension
import org.junit.jupiter.api.extension.TestTemplateInvocationContext
class RetryTemplateContext(
private val invocation: Int,
private val maxInvocations: Int,
private val minSuccess: Int
) : TestTemplateInvocationContext {
override fun getDisplayName(invocationIndex: Int): String {
return "Invocation number $invocationIndex (requires $minSuccess success)"
}
override fun getAdditionalExtensions(): MutableList<Extension> {
return mutableListOf(
RetryingTestExecutionExtension(invocation, maxInvocations, minSuccess)
)
}
}
Если вы запускаете тесты через Maven, с Surefire вы заботитесь о повторном запуске неудачных тестов автоматически с помощью rerunFailingTestsCount
.
однако, начиная с 2.21.0, это не работает для JUnit 5 (только 4.икс.) Но, надеюсь, он будет поддержан в следующих выпусках.
U может попробовать это расширение для junit 5.
<dependency>
<groupId>io.github.artsok</groupId>
<artifactId>rerunner-jupiter</artifactId>
<version>LATEST</version>
</dependency>
примеры:
/**
* Repeated three times if test failed.
* By default Exception.class will be handled in test
*/
@RepeatedIfExceptionsTest(repeats = 3)
void reRunTest() throws IOException {
throw new IOException("Error in Test");
}
/**
* Repeated two times if test failed. Set IOException.class that will be handled in test
* @throws IOException - error occurred
*/
@RepeatedIfExceptionsTest(repeats = 2, exceptions = IOException.class)
void reRunTest2() throws IOException {
throw new IOException("Exception in I/O operation");
}
/**
* Repeated ten times if test failed. Set IOException.class that will be handled in test
* Set formatter for test. Like behavior as at {@link org.junit.jupiter.api.RepeatedTest}
* @throws IOException - error occurred
*/
@RepeatedIfExceptionsTest(repeats = 10, exceptions = IOException.class,
name = "Rerun failed test. Attempt {currentRepetition} of {totalRepetitions}")
void reRunTest3() throws IOException {
throw new IOException("Exception in I/O operation");
}
/**
* Repeated 100 times with minimum success four times, then disabled all remaining repeats.
* See image below how it works. Default exception is Exception.class
*/
@DisplayName("Test Case Name")
@RepeatedIfExceptionsTest(repeats = 100, minSuccess = 4)
void reRunTest4() {
if(random.nextInt() % 2 == 0) {
throw new RuntimeException("Error in Test");
}
}
просмотр в IDEA:
с минимальным успехом четыре раза затем отключает все остальные:
вы также можете смешать @RepeatedIfExceptionsTest с @DisplayName