Skip to content

Commit 0ca8a91

Browse files
committed
GH-9492: Add tests and extend fix to MockIntegrationContext
Switches `MockIntegrationContextCustomizerFactory` to use `TestContextAnnotationUtils` in order to properly support `@NestedTestConfiguration` semantics. Adds an integration test with a base class and several `@Nested` inner test classes to verify the various permutations of `@SpringIntegrationTest` inherit/override behavior when used w/ `@NestedTestConfiguration`.
1 parent abe382b commit 0ca8a91

File tree

4 files changed

+143
-26
lines changed

4 files changed

+143
-26
lines changed

spring-integration-test/src/main/java/org/springframework/integration/test/context/MockIntegrationContextCustomizerFactory.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2022 the original author or authors.
2+
* Copyright 2017-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,17 +18,18 @@
1818

1919
import java.util.List;
2020

21-
import org.springframework.core.annotation.AnnotatedElementUtils;
2221
import org.springframework.test.context.ContextConfigurationAttributes;
2322
import org.springframework.test.context.ContextCustomizer;
2423
import org.springframework.test.context.ContextCustomizerFactory;
24+
import org.springframework.test.context.TestContextAnnotationUtils;
2525

2626
/**
2727
* The {@link ContextCustomizerFactory} implementation to produce a
2828
* {@link MockIntegrationContextCustomizer} if a {@link SpringIntegrationTest} annotation
2929
* is present on the test class.
3030
*
3131
* @author Artem Bilan
32+
* @author Chris Bono
3233
*
3334
* @since 5.0
3435
*/
@@ -38,7 +39,7 @@ class MockIntegrationContextCustomizerFactory implements ContextCustomizerFactor
3839
public ContextCustomizer createContextCustomizer(Class<?> testClass,
3940
List<ContextConfigurationAttributes> configAttributes) {
4041

41-
return AnnotatedElementUtils.hasAnnotation(testClass, SpringIntegrationTest.class)
42+
return TestContextAnnotationUtils.hasAnnotation(testClass, SpringIntegrationTest.class)
4243
? new MockIntegrationContextCustomizer()
4344
: null;
4445
}

spring-integration-test/src/main/java/org/springframework/integration/test/context/SpringIntegrationTestExecutionListener.java

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2022 the original author or authors.
2+
* Copyright 2017-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@
1818

1919
import java.util.Arrays;
2020

21-
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
2221
import org.springframework.context.ApplicationContext;
2322
import org.springframework.integration.endpoint.AbstractEndpoint;
2423
import org.springframework.test.context.TestContext;
@@ -45,11 +44,7 @@ public void prepareTestInstance(TestContext testContext) {
4544
String[] patterns = springIntegrationTest != null ? springIntegrationTest.noAutoStartup() : new String[0];
4645

4746
ApplicationContext applicationContext = testContext.getApplicationContext();
48-
MockIntegrationContext mockIntegrationContext = handledGetMockIntegrationContext(applicationContext);
49-
if (mockIntegrationContext == null) {
50-
return;
51-
}
52-
47+
MockIntegrationContext mockIntegrationContext = applicationContext.getBean(MockIntegrationContext.class);
5348
mockIntegrationContext.getAutoStartupCandidates()
5449
.stream()
5550
.filter(endpoint -> !match(endpoint.getBeanName(), patterns))
@@ -60,11 +55,7 @@ public void prepareTestInstance(TestContext testContext) {
6055
@Override
6156
public void afterTestClass(TestContext testContext) {
6257
ApplicationContext applicationContext = testContext.getApplicationContext();
63-
MockIntegrationContext mockIntegrationContext = handledGetMockIntegrationContext(applicationContext);
64-
if (mockIntegrationContext == null) {
65-
return;
66-
}
67-
58+
MockIntegrationContext mockIntegrationContext = applicationContext.getBean(MockIntegrationContext.class);
6859
mockIntegrationContext.getAutoStartupCandidates()
6960
.forEach(AbstractEndpoint::stop);
7061
}
@@ -75,15 +66,4 @@ private boolean match(String name, String[] patterns) {
7566
.anyMatch(pattern -> PatternMatchUtils.simpleMatch(pattern, name));
7667
}
7768

78-
/**
79-
* to allow nested class execution
80-
*/
81-
private MockIntegrationContext handledGetMockIntegrationContext(ApplicationContext applicationContext) {
82-
try {
83-
return applicationContext.getBean(MockIntegrationContext.class);
84-
} catch (NoSuchBeanDefinitionException e) {
85-
return null;
86-
}
87-
}
88-
8969
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2024-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.integration.test.context;
18+
19+
import org.springframework.context.annotation.Bean;
20+
import org.springframework.context.annotation.Configuration;
21+
import org.springframework.integration.config.EnableIntegration;
22+
import org.springframework.integration.endpoint.AbstractEndpoint;
23+
import org.springframework.integration.endpoint.ReactiveMessageSourceProducer;
24+
import org.springframework.messaging.support.GenericMessage;
25+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
26+
27+
/**
28+
* Base integration test that specifies a default {@link SpringIntegrationTest}
29+
* to be inherited by concrete subclasses.
30+
*
31+
* @author Chris Bono
32+
* @since 6.4.0
33+
*/
34+
@SpringJUnitConfig
35+
@SpringIntegrationTest(noAutoStartup = "*")
36+
class AbstractIntegrationTest {
37+
38+
@Configuration(proxyBeanMethods = false)
39+
@EnableIntegration
40+
static class MockEndpointConfig {
41+
42+
@Bean
43+
AbstractEndpoint mockEndpoint() {
44+
ReactiveMessageSourceProducer endpoint = new ReactiveMessageSourceProducer(() -> new GenericMessage<>("testFromMockEndpoint"));
45+
endpoint.setOutputChannelName("nullChannel");
46+
return endpoint;
47+
}
48+
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright 2024-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.integration.test.context;
18+
19+
import org.junit.jupiter.api.Nested;
20+
import org.junit.jupiter.api.Test;
21+
22+
import org.springframework.beans.factory.annotation.Autowired;
23+
import org.springframework.integration.endpoint.AbstractEndpoint;
24+
import org.springframework.test.context.ContextConfiguration;
25+
import org.springframework.test.context.NestedTestConfiguration;
26+
27+
import static org.assertj.core.api.Assertions.assertThat;
28+
29+
/**
30+
* Concrete specialization of {@link AbstractIntegrationTest} used to
31+
* test inherit and override behavior of {@link SpringIntegrationTest}
32+
* when used with {@link Nested} and {@link NestedTestConfiguration}.
33+
*
34+
* @author Chris Bono
35+
* @since 6.4.0
36+
*/
37+
class NestedSpringIntegrationTestAnnotationTests extends AbstractIntegrationTest {
38+
39+
@Test
40+
void annotationDefinedOnParentIsInheritedByDefault(@Autowired AbstractEndpoint mockEndpoint) {
41+
// parent disables startup for all endpoints
42+
assertThat(mockEndpoint.isRunning()).isFalse();
43+
}
44+
45+
@Nested
46+
class NestedTestWithoutEnclosingConfiguration {
47+
48+
@Test
49+
void annotationDefinedOnParentOfEnclosingIsInheritedByDefault(@Autowired AbstractEndpoint mockEndpoint) {
50+
assertThat(mockEndpoint.isRunning()).isFalse();
51+
}
52+
}
53+
54+
@Nested
55+
@NestedTestConfiguration(NestedTestConfiguration.EnclosingConfiguration.INHERIT)
56+
class NestedTestWithInheritEnclosingConfiguration {
57+
58+
@Test
59+
void annotationDefinedOnParentOfEnclosingIsInherited(@Autowired AbstractEndpoint mockEndpoint) {
60+
assertThat(mockEndpoint.isRunning()).isFalse();
61+
}
62+
}
63+
64+
@Nested
65+
@NestedTestConfiguration(NestedTestConfiguration.EnclosingConfiguration.INHERIT)
66+
@SpringIntegrationTest(noAutoStartup = "noSuchEndpointWithThisPatternExists")
67+
class NestedTestWithInheritEnclosingConfigurationButOverrideAnnotation {
68+
69+
@Test
70+
void annotationDefinedOnParentOfEnclosingIsOverridden(@Autowired AbstractEndpoint mockEndpoint) {
71+
assertThat(mockEndpoint.isRunning()).isTrue();
72+
}
73+
}
74+
75+
@Nested
76+
@NestedTestConfiguration(NestedTestConfiguration.EnclosingConfiguration.OVERRIDE)
77+
@ContextConfiguration(classes = MockEndpointConfig.class)
78+
class NestedTestWithOverrideEnclosingConfiguration {
79+
80+
@Test
81+
void annotationDefinedOnParentOfEnclosingIsInherited(@Autowired AbstractEndpoint mockEndpoint) {
82+
assertThat(mockEndpoint.isRunning()).isTrue();
83+
}
84+
}
85+
86+
}

0 commit comments

Comments
 (0)