diff --git a/spring-rabbit-junit/src/main/java/org/springframework/amqp/rabbit/junit/LogLevels.java b/spring-rabbit-junit/src/main/java/org/springframework/amqp/rabbit/junit/LogLevels.java index de34361d..6ede6cd9 100644 --- a/spring-rabbit-junit/src/main/java/org/springframework/amqp/rabbit/junit/LogLevels.java +++ b/spring-rabbit-junit/src/main/java/org/springframework/amqp/rabbit/junit/LogLevels.java @@ -53,8 +53,8 @@ public @interface LogLevels { /** * The Log4j level name to switch the categories to during the test. - * @return the level (default DEBUG). + * @return the level (default Log4j {@code Levels.toLevel()} - currently, DEBUG). */ - String level() default "DEBUG"; + String level() default ""; } diff --git a/spring-rabbit-junit/src/main/java/org/springframework/amqp/rabbit/junit/LogLevelsCondition.java b/spring-rabbit-junit/src/main/java/org/springframework/amqp/rabbit/junit/LogLevelsCondition.java index bc02d994..f307af59 100644 --- a/spring-rabbit-junit/src/main/java/org/springframework/amqp/rabbit/junit/LogLevelsCondition.java +++ b/spring-rabbit-junit/src/main/java/org/springframework/amqp/rabbit/junit/LogLevelsCondition.java @@ -17,12 +17,17 @@ package org.springframework.amqp.rabbit.junit; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Method; import java.util.Arrays; +import java.util.Map; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.commons.logging.LogFactory; import org.apache.logging.log4j.Level; import org.junit.jupiter.api.extension.AfterAllCallback; import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ConditionEvaluationResult; import org.junit.jupiter.api.extension.ExecutionCondition; @@ -33,6 +38,7 @@ import org.junit.jupiter.api.extension.ExtensionContext.Store; import org.springframework.amqp.rabbit.junit.JUnitUtils.LevelsContainer; import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotations; +import org.springframework.core.log.LogAccessor; /** * JUnit condition that adjusts and reverts log levels before/after each test. @@ -42,7 +48,9 @@ import org.springframework.core.annotation.MergedAnnotations; * */ public class LogLevelsCondition - implements ExecutionCondition, BeforeEachCallback, AfterEachCallback, AfterAllCallback { + implements ExecutionCondition, BeforeEachCallback, AfterEachCallback, BeforeAllCallback, AfterAllCallback { + + private static final LogAccessor logger = new LogAccessor(LogFactory.getLog(LogLevelsCondition.class)); private static final String STORE_ANNOTATION_KEY = "logLevelsAnnotation"; @@ -51,6 +59,8 @@ public class LogLevelsCondition private static final ConditionEvaluationResult ENABLED = ConditionEvaluationResult.enabled("@LogLevels always enabled"); + private final Map loggedMethods = new ConcurrentHashMap<>(); + @Override public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { Optional element = context.getElement(); @@ -66,14 +76,9 @@ public class LogLevelsCondition } @Override - public void beforeEach(ExtensionContext context) { + public void beforeAll(ExtensionContext context) { Store store = context.getStore(Namespace.create(getClass(), context)); LogLevels logLevels = store.get(STORE_ANNOTATION_KEY, LogLevels.class); - if (logLevels == null) { - ExtensionContext parent = context.getParent().get(); - store = parent.getStore(Namespace.create(getClass(), parent)); - logLevels = store.get(STORE_ANNOTATION_KEY, LogLevels.class); - } if (logLevels != null) { store.put(STORE_CONTAINER_KEY, JUnitUtils.adjustLogLevels(context.getDisplayName(), Arrays.asList((logLevels.classes())), @@ -82,22 +87,36 @@ public class LogLevelsCondition } } + @Override + public void beforeEach(ExtensionContext context) { + Store store = context.getStore(Namespace.create(getClass(), context)); + LogLevels logLevels = store.get(STORE_ANNOTATION_KEY, LogLevels.class); + if (logLevels != null) { // Method level annotation + if (store.get(STORE_CONTAINER_KEY) == null) { + store.put(STORE_CONTAINER_KEY, JUnitUtils.adjustLogLevels(context.getDisplayName(), + Arrays.asList((logLevels.classes())), + Arrays.asList(logLevels.categories()), + Level.toLevel(logLevels.level()))); + } + } + else { + Optional testMethod = context.getTestMethod(); + if (testMethod.isPresent() + && this.loggedMethods.putIfAbsent(testMethod.get().getName(), Boolean.TRUE) == null) { + logger.info(() -> "+++++++++++++++++++++++++++++ Begin " + testMethod.get().getName()); + } + } + } + @Override public void afterEach(ExtensionContext context) { Store store = context.getStore(Namespace.create(getClass(), context)); LevelsContainer container = store.get(STORE_CONTAINER_KEY, LevelsContainer.class); - boolean parentStore = false; - if (container == null) { - ExtensionContext parent = context.getParent().get(); - store = parent.getStore(Namespace.create(getClass(), parent)); - container = store.get(STORE_CONTAINER_KEY, LevelsContainer.class); - parentStore = true; - } if (container != null) { - JUnitUtils.revertLevels(context.getDisplayName(), container); - store.remove(STORE_CONTAINER_KEY); - if (!parentStore) { - store.remove(STORE_ANNOTATION_KEY); + LogLevels logLevels = store.get(STORE_ANNOTATION_KEY, LogLevels.class); + if (logLevels != null) { + JUnitUtils.revertLevels(context.getDisplayName(), container); + store.remove(STORE_CONTAINER_KEY); } } } @@ -105,7 +124,13 @@ public class LogLevelsCondition @Override public void afterAll(ExtensionContext context) { Store store = context.getStore(Namespace.create(getClass(), context)); - store.remove(STORE_ANNOTATION_KEY); + LogLevels logLevels = store.remove(STORE_ANNOTATION_KEY, LogLevels.class); + if (logLevels != null) { + LevelsContainer container = store.get(STORE_CONTAINER_KEY, LevelsContainer.class); + JUnitUtils.revertLevels(context.getDisplayName(), container); + store.remove(STORE_CONTAINER_KEY); + } + this.loggedMethods.clear(); } } diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePerformanceIntegrationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePerformanceIntegrationTests.java index 88afe8c0..a1429747 100755 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePerformanceIntegrationTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitTemplatePerformanceIntegrationTests.java @@ -18,19 +18,22 @@ package org.springframework.amqp.rabbit.core; import static org.assertj.core.api.Assertions.assertThat; -import org.apache.logging.log4j.Level; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.RepeatedTest; import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; -import org.springframework.amqp.rabbit.junit.BrokerRunning; import org.springframework.amqp.rabbit.junit.BrokerTestUtils; -import org.springframework.amqp.rabbit.junit.LogLevelAdjuster; -import org.springframework.amqp.rabbit.junit.LongRunningIntegrationTest; -import org.springframework.amqp.rabbit.test.RepeatProcessor; -import org.springframework.test.annotation.Repeat; +import org.springframework.amqp.rabbit.junit.LogLevels; +import org.springframework.amqp.rabbit.junit.RabbitAvailable; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.transaction.support.AbstractPlatformTransactionManager; @@ -44,87 +47,77 @@ import org.springframework.transaction.support.TransactionTemplate; * @since 1.0 * */ +@RabbitAvailable(queues = RabbitTemplatePerformanceIntegrationTests.ROUTE) +@LogLevels(level = "ERROR", classes = RabbitTemplate.class) public class RabbitTemplatePerformanceIntegrationTests { - private static final String ROUTE = "test.queue"; + public static final String ROUTE = "test.queue.RabbitTemplatePerformanceIntegrationTests"; - private final RabbitTemplate template = new RabbitTemplate(); + private static final RabbitTemplate template = new RabbitTemplate(); - @Rule - public LongRunningIntegrationTest longTests = new LongRunningIntegrationTest(); + private static final ExecutorService exec = Executors.newFixedThreadPool(4); - @Rule - public RepeatProcessor repeat = new RepeatProcessor(4); + private static CachingConnectionFactory connectionFactory; - @Rule - // After the repeat processor, so it only runs once - public LogLevelAdjuster logLevels = new LogLevelAdjuster(Level.ERROR, RabbitTemplate.class); - - @Rule - // After the repeat processor, so it only runs once - public BrokerRunning brokerIsRunning = BrokerRunning.isRunningWithEmptyQueues(ROUTE); - - private CachingConnectionFactory connectionFactory; - - @Before - public void declareQueue() { - if (repeat.isInitialized()) { - // Important to prevent concurrent re-initialization - return; - } + @BeforeAll + public static void declareQueue() { connectionFactory = new CachingConnectionFactory(); connectionFactory.setHost("localhost"); - connectionFactory.setChannelCacheSize(repeat.getConcurrency()); connectionFactory.setPort(BrokerTestUtils.getPort()); template.setConnectionFactory(connectionFactory); } - @After - public void cleanUp() { - if (!repeat.isFinalizing()) { - return; - } - this.template.stop(); - this.connectionFactory.destroy(); - this.brokerIsRunning.removeTestQueues(); + @AfterAll + public static void cleanUp() { + template.stop(); + connectionFactory.destroy(); + exec.shutdownNow(); } - @Test - @Repeat(200) - public void testSendAndReceive() throws Exception { - template.convertAndSend(ROUTE, "message"); - String result = (String) template.receiveAndConvert(ROUTE); - int count = 5; - while (result == null && count-- > 0) { - /* - * Retry for the purpose of non-transacted case because channel operations are async in that case - */ - Thread.sleep(10L); - result = (String) template.receiveAndConvert(ROUTE); - } - assertThat(result).isEqualTo("message"); - } - - @Test - @Repeat(200) - public void testSendAndReceiveTransacted() throws Exception { - template.setChannelTransacted(true); - template.convertAndSend(ROUTE, "message"); - String result = (String) template.receiveAndConvert(ROUTE); - assertThat(result).isEqualTo("message"); - } - - @Test - @Repeat(200) - public void testSendAndReceiveExternalTransacted() throws Exception { - template.setChannelTransacted(true); - new TransactionTemplate(new TestTransactionManager()).execute(status -> { + @RepeatedTest(50) + public void testSendAndReceive() throws InterruptedException { + CountDownLatch latch = new CountDownLatch(4); + List results = new ArrayList<>(); + Stream.of(1, 2, 3, 4).forEach(i -> exec.execute(() -> { template.convertAndSend(ROUTE, "message"); - return null; - }); - template.convertAndSend(ROUTE, "message"); - String result = (String) template.receiveAndConvert(ROUTE); - assertThat(result).isEqualTo("message"); + results.add((String) template.receiveAndConvert(ROUTE, 10_000L)); + latch.countDown(); + })); + assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + assertThat(results).contains("message", "message", "message", "message"); + } + + @RepeatedTest(50) + public void testSendAndReceiveTransacted() throws InterruptedException { + CountDownLatch latch = new CountDownLatch(4); + List results = new ArrayList<>(); + template.setChannelTransacted(true); + Stream.of(1, 2, 3, 4).forEach(i -> exec.execute(() -> { + template.convertAndSend(ROUTE, "message"); + results.add((String) template.receiveAndConvert(ROUTE, 10_000L)); + latch.countDown(); + })); + assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + assertThat(results).contains("message", "message", "message", "message"); + } + + @RepeatedTest(50) + public void testSendAndReceiveExternalTransacted() throws InterruptedException { + template.setChannelTransacted(true); + CountDownLatch latch = new CountDownLatch(4); + List results = new ArrayList<>(); + template.setChannelTransacted(true); + Stream.of(1, 2, 3, 4).forEach(i -> exec.execute(() -> { + new TransactionTemplate(new TestTransactionManager()).execute(status -> { + template.convertAndSend(ROUTE, "message"); + return null; + }); + template.convertAndSend(ROUTE, "message"); + results.add((String) template.receiveAndConvert(ROUTE, 10_000L)); + latch.countDown(); + })); + assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); + assertThat(results).contains("message", "message", "message", "message"); } @SuppressWarnings("serial") diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/MessageListenerContainerRetryIntegrationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/MessageListenerContainerRetryIntegrationTests.java index 9804bdea..a87ccf5c 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/MessageListenerContainerRetryIntegrationTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/MessageListenerContainerRetryIntegrationTests.java @@ -27,10 +27,8 @@ import java.util.concurrent.atomic.AtomicInteger; import org.aopalliance.aop.Advice; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.logging.log4j.Level; -import org.junit.After; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.api.Test; import org.springframework.amqp.core.AcknowledgeMode; import org.springframework.amqp.core.Queue; @@ -39,18 +37,16 @@ import org.springframework.amqp.rabbit.config.StatefulRetryOperationsInterceptor import org.springframework.amqp.rabbit.config.StatelessRetryOperationsInterceptorFactoryBean; import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; import org.springframework.amqp.rabbit.core.RabbitTemplate; -import org.springframework.amqp.rabbit.junit.BrokerRunning; import org.springframework.amqp.rabbit.junit.BrokerTestUtils; -import org.springframework.amqp.rabbit.junit.LogLevelAdjuster; +import org.springframework.amqp.rabbit.junit.LogLevels; +import org.springframework.amqp.rabbit.junit.RabbitAvailable; import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; -import org.springframework.amqp.rabbit.test.RepeatProcessor; import org.springframework.amqp.support.converter.MessageConverter; import org.springframework.amqp.support.converter.SimpleMessageConverter; import org.springframework.amqp.utils.SerializationUtils; import org.springframework.beans.factory.DisposableBean; import org.springframework.retry.policy.MapRetryContextCache; import org.springframework.retry.support.RetryTemplate; -import org.springframework.test.annotation.Repeat; /** * @author Dave Syer @@ -61,25 +57,17 @@ import org.springframework.test.annotation.Repeat; * @since 1.0 * */ +@RabbitAvailable(queues = MessageListenerContainerRetryIntegrationTests.TEST_QUEUE) +@LogLevels(level = "ERROR", classes = { + RabbitTemplate.class, SimpleMessageListenerContainer.class, BlockingQueueConsumer.class, + StatefulRetryOperationsInterceptorFactoryBean.class, MessageListenerContainerRetryIntegrationTests.class }) public class MessageListenerContainerRetryIntegrationTests { + public static final String TEST_QUEUE = "test.queue.MessageListenerContainerRetryIntegrationTests"; + private static Log logger = LogFactory.getLog(MessageListenerContainerRetryIntegrationTests.class); - private static Queue queue = new Queue("test.queue"); - - @Rule - public BrokerRunning brokerIsRunning = BrokerRunning.isRunningWithEmptyQueues(queue.getName()); - - @Rule - public LogLevelAdjuster logLevels = new LogLevelAdjuster(Level.ERROR, RabbitTemplate.class, - SimpleMessageListenerContainer.class, BlockingQueueConsumer.class); - - @Rule - public LogLevelAdjuster traceLevels = new LogLevelAdjuster(Level.ERROR, - StatefulRetryOperationsInterceptorFactoryBean.class, MessageListenerContainerRetryIntegrationTests.class); - - @Rule - public RepeatProcessor repeats = new RepeatProcessor(); + private static Queue queue = new Queue(TEST_QUEUE); private RetryTemplate retryTemplate; @@ -93,21 +81,14 @@ public class MessageListenerContainerRetryIntegrationTests { connectionFactory.setPort(BrokerTestUtils.getPort()); template.setConnectionFactory(connectionFactory); if (messageConverter == null) { - SimpleMessageConverter messageConverter = new SimpleMessageConverter(); - messageConverter.setCreateMessageIds(true); - this.messageConverter = messageConverter; + SimpleMessageConverter converter = new SimpleMessageConverter(); + converter.setCreateMessageIds(true); + this.messageConverter = converter; } template.setMessageConverter(messageConverter); return template; } - @After - public void tearDown() { - if (this.repeats.isFinalizing()) { - this.brokerIsRunning.removeTestQueues(); - } - } - @Test public void testStatefulRetryWithAllMessagesFailing() throws Exception { @@ -153,8 +134,7 @@ public class MessageListenerContainerRetryIntegrationTests { .hasMessageContaining("but was not."); } - @Test - @Repeat(10) + @RepeatedTest(10) public void testStatefulRetryWithTxSizeAndIntermittentFailure() throws Exception { int messageCount = 10; diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/MessageListenerRecoveryRepeatIntegrationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/MessageListenerRecoveryRepeatIntegrationTests.java index 64949b65..b61603dc 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/MessageListenerRecoveryRepeatIntegrationTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/listener/MessageListenerRecoveryRepeatIntegrationTests.java @@ -25,11 +25,12 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.logging.log4j.Level; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.api.RepetitionInfo; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; import org.springframework.amqp.core.AcknowledgeMode; import org.springframework.amqp.core.Message; @@ -37,15 +38,13 @@ import org.springframework.amqp.core.Queue; import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.core.RabbitTemplate; -import org.springframework.amqp.rabbit.junit.BrokerRunning; import org.springframework.amqp.rabbit.junit.BrokerTestUtils; -import org.springframework.amqp.rabbit.junit.LogLevelAdjuster; +import org.springframework.amqp.rabbit.junit.LogLevels; +import org.springframework.amqp.rabbit.junit.RabbitAvailable; import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener; import org.springframework.amqp.rabbit.listener.exception.FatalListenerExecutionException; -import org.springframework.amqp.rabbit.test.RepeatProcessor; import org.springframework.beans.factory.DisposableBean; -import org.springframework.test.annotation.Repeat; import com.rabbitmq.client.Channel; @@ -57,13 +56,19 @@ import com.rabbitmq.client.Channel; * @author Gary Russell * */ +@RabbitAvailable(queues = MessageListenerRecoveryRepeatIntegrationTests.TEST_QUEUE, purgeAfterEach = false) +@LogLevels(level = "ERROR", classes = { RabbitTemplate.class, + ConditionalRejectingErrorHandler.class, + SimpleMessageListenerContainer.class, BlockingQueueConsumer.class, + MessageListenerRecoveryRepeatIntegrationTests.class }) +@TestInstance(Lifecycle.PER_CLASS) public class MessageListenerRecoveryRepeatIntegrationTests { + public static final String TEST_QUEUE = "test.queue.MessageListenerRecoveryRepeatIntegrationTests"; + private static Log logger = LogFactory.getLog(MessageListenerRecoveryRepeatIntegrationTests.class); - private final Queue queue = new Queue("test.queue"); - - private final Queue sendQueue = new Queue("test.send"); + private final Queue queue = new Queue(TEST_QUEUE); private final int concurrentConsumers = 1; @@ -77,33 +82,22 @@ public class MessageListenerRecoveryRepeatIntegrationTests { private SimpleMessageListenerContainer container; - @Rule - public LogLevelAdjuster logLevels = new LogLevelAdjuster(Level.ERROR, RabbitTemplate.class, - ConditionalRejectingErrorHandler.class, - SimpleMessageListenerContainer.class, BlockingQueueConsumer.class, MessageListenerRecoveryRepeatIntegrationTests.class); - - @Rule - public BrokerRunning brokerIsRunning = BrokerRunning.isRunningWithEmptyQueues(queue.getName(), sendQueue.getName()); - - @Rule - public RepeatProcessor repeatProcessor = new RepeatProcessor(); - private CloseConnectionListener listener; private ConnectionFactory connectionFactory; - @Before - public void init() { - if (!repeatProcessor.isInitialized()) { + @BeforeEach + public void init(RepetitionInfo info) { + if (info.getCurrentRepetition() == 1) { logger.info("Initializing at start of test"); connectionFactory = createConnectionFactory(); listener = new CloseConnectionListener(); } } - @After - public void clear() throws Exception { - if (repeatProcessor.isFinalizing()) { + @AfterEach + public void clear(RepetitionInfo info) throws Exception { + if (info.getCurrentRepetition() == info.getTotalRepetitions()) { // Wait for broker communication to finish before trying to stop container Thread.sleep(300L); logger.info("Shutting down at end of test"); @@ -113,12 +107,10 @@ public class MessageListenerRecoveryRepeatIntegrationTests { if (connectionFactory != null) { ((DisposableBean) connectionFactory).destroy(); } - this.brokerIsRunning.removeTestQueues(); } } - @Test - @Repeat(1000) + @RepeatedTest(1000) public void testListenerRecoversFromClosedConnection() throws Exception { if (this.container == null) { this.container = createContainer(queue.getName(), listener, connectionFactory); @@ -163,6 +155,7 @@ public class MessageListenerRecoveryRepeatIntegrationTests { container.setChannelTransacted(transactional); container.setAcknowledgeMode(acknowledgeMode); container.setTaskExecutor(Executors.newFixedThreadPool(concurrentConsumers)); + container.setReceiveTimeout(100L); container.afterPropertiesSet(); container.start(); return container; diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/test/RepeatProcessor.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/test/RepeatProcessor.java index 2ead80b6..7d31b0c3 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/test/RepeatProcessor.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/test/RepeatProcessor.java @@ -34,6 +34,7 @@ import org.junit.After; import org.junit.Before; import org.junit.internal.runners.statements.RunAfters; import org.junit.internal.runners.statements.RunBefores; +import org.junit.jupiter.api.RepeatedTest; import org.junit.rules.MethodRule; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; @@ -46,10 +47,12 @@ import org.springframework.test.annotation.Repeat; * A JUnit method @Rule that looks at Spring repeat annotations on methods and executes the test multiple times * (without re-initializing the test case if necessary). To avoid re-initializing use the {@link #isInitialized()} * method to protect the @Before and @After methods. + * @deprecated in favor of JUnit 5 {@link RepeatedTest}. * * @author Dave Syer * */ +@Deprecated public class RepeatProcessor implements MethodRule { private static final Log logger = LogFactory.getLog(RepeatProcessor.class);