diff --git a/spring-integration-test/src/main/java/org/springframework/integration/test/context/IntegrationEndpointsInitializer.java b/spring-integration-test/src/main/java/org/springframework/integration/test/context/IntegrationEndpointsInitializer.java deleted file mode 100644 index 2ac6e9c7b64..00000000000 --- a/spring-integration-test/src/main/java/org/springframework/integration/test/context/IntegrationEndpointsInitializer.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2017-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.integration.test.context; - -import java.util.Arrays; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.SmartInitializingSingleton; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.integration.endpoint.AbstractEndpoint; -import org.springframework.util.Assert; -import org.springframework.util.PatternMatchUtils; - -/** - * A component to customize {@link AbstractEndpoint} beans according - * to the provided options in the {@link SpringIntegrationTest} annotation - * after all beans are registered in the application context but before its refresh. - *
- * This class implements both {@link SmartInitializingSingleton} and {@link BeanPostProcessor}
- * to cover all the possible variants of {@link AbstractEndpoint} beans registration.
- * First of all a bean for this class is registered in the application context, when XML configurations
- * are parsed and registered already by the Spring Testing Framework, therefore a
- * {@link BeanPostProcessor#postProcessBeforeInitialization(Object, String)} hook is not called for those beans.
- * On the other hand we can't always rely on just a {@link SmartInitializingSingleton#afterSingletonsInstantiated()}
- * because {@link SmartInitializingSingleton} beans are not ordered and some implementations may register beans
- * later, than this {@link #afterSingletonsInstantiated()} is called.
- * Plus beans might be registered at runtime, therefore {@link #postProcessBeforeInitialization(Object, String)}
- * is still applied.
- *
- * @author Artem Bilan
- *
- * @since 5.0
- */
-class IntegrationEndpointsInitializer implements SmartInitializingSingleton, BeanPostProcessor, BeanFactoryAware {
-
- private final String[] patterns;
-
- private ConfigurableListableBeanFactory beanFactory;
-
- IntegrationEndpointsInitializer(SpringIntegrationTest springIntegrationTest) {
- this.patterns = springIntegrationTest.noAutoStartup();
- }
-
- @Override
- public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
- Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory);
- this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
- }
-
- @Override
- public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
- if (bean instanceof AbstractEndpoint && ((AbstractEndpoint) bean).isAutoStartup() && match(beanName)) {
- ((AbstractEndpoint) bean).setAutoStartup(false);
- }
- return bean;
- }
-
- @Override
- public void afterSingletonsInstantiated() {
- this.beanFactory.getBeansOfType(AbstractEndpoint.class)
- .entrySet()
- .stream()
- .filter(entry -> entry.getValue().isAutoStartup() && match(entry.getKey()))
- .forEach(entry -> entry.getValue().setAutoStartup(false));
- }
-
- private boolean match(String name) {
- return Arrays.stream(this.patterns)
- .anyMatch(pattern -> PatternMatchUtils.simpleMatch(pattern, name));
- }
-
-}
diff --git a/spring-integration-test/src/main/java/org/springframework/integration/test/context/MockIntegrationContext.java b/spring-integration-test/src/main/java/org/springframework/integration/test/context/MockIntegrationContext.java
index 199bd33763d..755467d7964 100644
--- a/spring-integration-test/src/main/java/org/springframework/integration/test/context/MockIntegrationContext.java
+++ b/spring-integration-test/src/main/java/org/springframework/integration/test/context/MockIntegrationContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2021 the original author or authors.
+ * Copyright 2017-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,20 +16,25 @@
package org.springframework.integration.test.context;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.SmartInitializingSingleton;
+import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.Lifecycle;
import org.springframework.context.SmartLifecycle;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.core.MessageSource;
+import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.endpoint.IntegrationConsumer;
import org.springframework.integration.endpoint.ReactiveStreamsConsumer;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
@@ -57,7 +62,7 @@
*
* @see SpringIntegrationTest
*/
-public class MockIntegrationContext implements BeanFactoryAware {
+public class MockIntegrationContext implements BeanPostProcessor, SmartInitializingSingleton, BeanFactoryAware {
private static final String HANDLER = "handler";
@@ -68,6 +73,8 @@ public class MockIntegrationContext implements BeanFactoryAware {
private final Map
- * Registers {@link MockIntegrationContext}, {@link IntegrationEndpointsInitializer} beans.
+ * Registers {@link MockIntegrationContext} bean.
*
* @author Artem Bilan
*
@@ -38,12 +35,6 @@
*/
class MockIntegrationContextCustomizer implements ContextCustomizer {
- private final SpringIntegrationTest springIntegrationTest;
-
- MockIntegrationContextCustomizer(SpringIntegrationTest springIntegrationTest) {
- this.springIntegrationTest = springIntegrationTest;
- }
-
@Override
public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
@@ -52,29 +43,16 @@ public void customizeContext(ConfigurableApplicationContext context, MergedConte
registry.registerBeanDefinition(MockIntegrationContext.MOCK_INTEGRATION_CONTEXT_BEAN_NAME,
new RootBeanDefinition(MockIntegrationContext.class));
-
- String endpointsInitializer = Introspector.decapitalize(IntegrationEndpointsInitializer.class.getSimpleName());
-
- registry.registerBeanDefinition(endpointsInitializer,
- BeanDefinitionBuilder.genericBeanDefinition(IntegrationEndpointsInitializer.class)
- .addConstructorArgValue(this.springIntegrationTest)
- .getBeanDefinition());
-
}
@Override
public int hashCode() {
- return this.springIntegrationTest.hashCode();
+ return MockIntegrationContextCustomizer.class.hashCode();
}
@Override
public boolean equals(Object obj) {
- if (obj == null || obj.getClass() != getClass()) {
- return false;
- }
-
- MockIntegrationContextCustomizer customizer = (MockIntegrationContextCustomizer) obj;
- return this.springIntegrationTest.equals(customizer.springIntegrationTest);
+ return obj != null && obj.getClass() == getClass();
}
}
diff --git a/spring-integration-test/src/main/java/org/springframework/integration/test/context/MockIntegrationContextCustomizerFactory.java b/spring-integration-test/src/main/java/org/springframework/integration/test/context/MockIntegrationContextCustomizerFactory.java
index fd9c28c8a96..a29d2eca965 100644
--- a/spring-integration-test/src/main/java/org/springframework/integration/test/context/MockIntegrationContextCustomizerFactory.java
+++ b/spring-integration-test/src/main/java/org/springframework/integration/test/context/MockIntegrationContextCustomizerFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,11 +38,8 @@ class MockIntegrationContextCustomizerFactory implements ContextCustomizerFactor
public ContextCustomizer createContextCustomizer(Class> testClass,
List
* The typical usage of this annotation is like:
*
- * @RunWith(SpringRunner.class)
+ * @SpringJUnitConfig
* @SpringIntegrationTest
* public class MyIntegrationTests {
*
@@ -60,6 +62,8 @@
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
+@TestExecutionListeners(listeners = SpringIntegrationTestExecutionListener.class,
+ mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS)
public @interface SpringIntegrationTest {
/**
@@ -68,9 +72,9 @@
* bean names to mark them as {@code autoStartup = false}
* during context initialization.
* @return the endpoints name patterns to stop during context initialization
- * @see IntegrationEndpointsInitializer
+ * @see SpringIntegrationTestExecutionListener
* @see org.springframework.util.PatternMatchUtils
*/
- String[] noAutoStartup() default {};
+ String[] noAutoStartup() default { };
}
diff --git a/spring-integration-test/src/main/java/org/springframework/integration/test/context/SpringIntegrationTestExecutionListener.java b/spring-integration-test/src/main/java/org/springframework/integration/test/context/SpringIntegrationTestExecutionListener.java
new file mode 100644
index 00000000000..1438d74481e
--- /dev/null
+++ b/spring-integration-test/src/main/java/org/springframework/integration/test/context/SpringIntegrationTestExecutionListener.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2017-2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.integration.test.context;
+
+import java.util.Arrays;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.integration.endpoint.AbstractEndpoint;
+import org.springframework.test.context.TestContext;
+import org.springframework.test.context.TestExecutionListener;
+import org.springframework.util.PatternMatchUtils;
+
+/**
+ * A {@link TestExecutionListener} to customize {@link AbstractEndpoint} beans according
+ * to the provided options in the {@link SpringIntegrationTest} annotation
+ * before and after test class phases.
+ *
+ * @author Artem Bilan
+ *
+ * @since 5.0
+ */
+class SpringIntegrationTestExecutionListener implements TestExecutionListener {
+
+ @Override
+ public void beforeTestClass(TestContext testContext) {
+ SpringIntegrationTest springIntegrationTest =
+ AnnotatedElementUtils.findMergedAnnotation(testContext.getTestClass(), SpringIntegrationTest.class);
+
+ String[] patterns = springIntegrationTest.noAutoStartup();
+
+ ApplicationContext applicationContext = testContext.getApplicationContext();
+ MockIntegrationContext mockIntegrationContext = applicationContext.getBean(MockIntegrationContext.class);
+ mockIntegrationContext.getAutoStartupCandidates()
+ .stream()
+ .filter(endpoint -> !match(endpoint.getBeanName(), patterns))
+ .peek(endpoint -> endpoint.setAutoStartup(true))
+ .forEach(AbstractEndpoint::start);
+ }
+
+ @Override
+ public void afterTestClass(TestContext testContext) {
+ ApplicationContext applicationContext = testContext.getApplicationContext();
+ MockIntegrationContext mockIntegrationContext = applicationContext.getBean(MockIntegrationContext.class);
+ mockIntegrationContext.getAutoStartupCandidates()
+ .forEach(AbstractEndpoint::stop);
+ }
+
+ private boolean match(String name, String[] patterns) {
+ return patterns.length > 0 &&
+ Arrays.stream(patterns)
+ .anyMatch(pattern -> PatternMatchUtils.simpleMatch(pattern, name));
+ }
+
+}
diff --git a/spring-integration-test/src/test/java/org/springframework/integration/test/mock/CachedSpringIntegrationTestAnnotationTests.java b/spring-integration-test/src/test/java/org/springframework/integration/test/mock/CachedSpringIntegrationTestAnnotationTests.java
index 4b309098463..6d4d1d5ede7 100644
--- a/spring-integration-test/src/test/java/org/springframework/integration/test/mock/CachedSpringIntegrationTestAnnotationTests.java
+++ b/spring-integration-test/src/test/java/org/springframework/integration/test/mock/CachedSpringIntegrationTestAnnotationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2019 the original author or authors.
+ * Copyright 2018-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,9 +20,11 @@
import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.test.context.SpringIntegrationTest;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
@@ -37,22 +39,28 @@ public abstract class CachedSpringIntegrationTestAnnotationTests {
private static int beanFactoryPostProcessorCallCounter;
+ @Autowired
+ protected AbstractEndpoint someEndpoint;
+
public static class SpringIntegrationTestAnnotationCaching1Tests
extends CachedSpringIntegrationTestAnnotationTests {
@Test
public void testSingleApplicationContext() {
assertThat(beanFactoryPostProcessorCallCounter).isEqualTo(1);
+ assertThat(this.someEndpoint.isRunning()).isTrue();
}
}
+ @SpringIntegrationTest(noAutoStartup = "someEndpoint")
public static class SpringIntegrationTestAnnotationCaching2Tests
extends CachedSpringIntegrationTestAnnotationTests {
@Test
public void testSingleApplicationContext() {
assertThat(beanFactoryPostProcessorCallCounter).isEqualTo(1);
+ assertThat(this.someEndpoint.isRunning()).isFalse();
}
}
@@ -65,6 +73,23 @@ public static BeanFactoryPostProcessor tesBeanFactoryPostProcessor() {
return beanFactory -> beanFactoryPostProcessorCallCounter++;
}
+ @Bean
+ public AbstractEndpoint someEndpoint() {
+ return new AbstractEndpoint() {
+
+ @Override
+ protected void doStart() {
+
+ }
+
+ @Override
+ protected void doStop() {
+
+ }
+
+ };
+ }
+
}
}
diff --git a/spring-integration-test/src/test/java/org/springframework/integration/test/mock/MockMessageSourceTests.java b/spring-integration-test/src/test/java/org/springframework/integration/test/mock/MockMessageSourceTests.java
index 8c2424b4be7..8aff663bb21 100644
--- a/spring-integration-test/src/test/java/org/springframework/integration/test/mock/MockMessageSourceTests.java
+++ b/spring-integration-test/src/test/java/org/springframework/integration/test/mock/MockMessageSourceTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,9 +19,8 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
-import org.junit.After;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -47,16 +46,14 @@
import org.springframework.messaging.Message;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
/**
* @author Artem Bilan
*
* @since 5.0
*/
-@RunWith(SpringRunner.class)
-@ContextConfiguration(classes = MockMessageSourceTests.Config.class)
+@SpringJUnitConfig(classes = MockMessageSourceTests.Config.class)
@SpringIntegrationTest(noAutoStartup = { "inboundChannelAdapter", "*Source*" })
@DirtiesContext
public class MockMessageSourceTests {
@@ -73,7 +70,7 @@ public class MockMessageSourceTests {
@Autowired
private IntegrationFlowContext integrationFlowContext;
- @After
+ @AfterEach
public void tearDown() {
this.mockIntegrationContext.resetBeans("mySourceEndpoint", "inboundChannelAdapter");
this.results.purge(null);
diff --git a/src/reference/asciidoc/testing.adoc b/src/reference/asciidoc/testing.adoc
index 88f6accbdeb..66758f9e37b 100644
--- a/src/reference/asciidoc/testing.adoc
+++ b/src/reference/asciidoc/testing.adoc
@@ -196,7 +196,7 @@ First we configure our test class with a `@SpringIntegrationTest` annotation to
====
[source,java]
----
-@RunWith(SpringRunner.class)
+@SpringJUnitConfig
@SpringIntegrationTest(noAutoStartup = {"inboundChannelAdapter", "*Source*"})
public class MyIntegrationTests {