Skip to content

Commit 9eca07c

Browse files
mtomikspring-builds
authored andcommitted
GH-9492: Honor @Nested in @SpringIntegrationTest
Fixes: #9492 Issue link: #9492 Switches `MockIntegrationContextCustomizerFactory` & `SpringIntegrationTestExecutionListener` 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`. (cherry picked from commit 3a8e3ab)
1 parent d8e3673 commit 9eca07c

File tree

6 files changed

+161
-7
lines changed

6 files changed

+161
-7
lines changed

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

Lines changed: 6 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,20 @@
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.
30+
* <p>
31+
* Honors the {@link org.springframework.test.context.NestedTestConfiguration} semantics.
3032
*
3133
* @author Artem Bilan
34+
* @author Chris Bono
3235
*
3336
* @since 5.0
3437
*/
@@ -38,7 +41,7 @@ class MockIntegrationContextCustomizerFactory implements ContextCustomizerFactor
3841
public ContextCustomizer createContextCustomizer(Class<?> testClass,
3942
List<ContextConfigurationAttributes> configAttributes) {
4043

41-
return AnnotatedElementUtils.hasAnnotation(testClass, SpringIntegrationTest.class)
44+
return TestContextAnnotationUtils.hasAnnotation(testClass, SpringIntegrationTest.class)
4245
? new MockIntegrationContextCustomizer()
4346
: null;
4447
}

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

Lines changed: 3 additions & 1 deletion
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.
@@ -51,6 +51,8 @@
5151
*
5252
* }
5353
* </pre>
54+
* <p>
55+
* Honors the {@link org.springframework.test.context.NestedTestConfiguration} semantics.
5456
*
5557
* @author Artem Bilan
5658
*

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

Lines changed: 3 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.
@@ -19,9 +19,9 @@
1919
import java.util.Arrays;
2020

2121
import org.springframework.context.ApplicationContext;
22-
import org.springframework.core.annotation.AnnotatedElementUtils;
2322
import org.springframework.integration.endpoint.AbstractEndpoint;
2423
import org.springframework.test.context.TestContext;
24+
import org.springframework.test.context.TestContextAnnotationUtils;
2525
import org.springframework.test.context.TestExecutionListener;
2626
import org.springframework.util.PatternMatchUtils;
2727

@@ -39,7 +39,7 @@ class SpringIntegrationTestExecutionListener implements TestExecutionListener {
3939
@Override
4040
public void prepareTestInstance(TestContext testContext) {
4141
SpringIntegrationTest springIntegrationTest =
42-
AnnotatedElementUtils.findMergedAnnotation(testContext.getTestClass(), SpringIntegrationTest.class);
42+
TestContextAnnotationUtils.findMergedAnnotation(testContext.getTestClass(), SpringIntegrationTest.class);
4343

4444
String[] patterns = springIntegrationTest != null ? springIntegrationTest.noAutoStartup() : new String[0];
4545

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 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+
*
33+
* @since 6.2.10
34+
*/
35+
@SpringJUnitConfig
36+
@SpringIntegrationTest(noAutoStartup = "*")
37+
class AbstractIntegrationTest {
38+
39+
@Configuration(proxyBeanMethods = false)
40+
@EnableIntegration
41+
static class MockEndpointConfig {
42+
43+
@Bean
44+
AbstractEndpoint mockEndpoint() {
45+
ReactiveMessageSourceProducer endpoint =
46+
new ReactiveMessageSourceProducer(() -> new GenericMessage<>("testFromMockEndpoint"));
47+
endpoint.setOutputChannelName("nullChannel");
48+
return endpoint;
49+
}
50+
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright 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.lang.Nullable;
25+
import org.springframework.test.context.ContextConfiguration;
26+
import org.springframework.test.context.NestedTestConfiguration;
27+
28+
import static org.assertj.core.api.Assertions.assertThat;
29+
30+
/**
31+
* Concrete specialization of {@link AbstractIntegrationTest} used to
32+
* test inherit and override behavior of {@link SpringIntegrationTest}
33+
* when used with {@link Nested} and {@link NestedTestConfiguration}.
34+
*
35+
* @author Chris Bono
36+
* @author Artem Bilan
37+
*
38+
* @since 6.2.10
39+
*/
40+
class NestedSpringIntegrationTestAnnotationTests extends AbstractIntegrationTest {
41+
42+
@Test
43+
void annotationDefinedOnParentIsInheritedByDefault(@Autowired AbstractEndpoint mockEndpoint) {
44+
assertThat(mockEndpoint.isRunning()).isFalse();
45+
}
46+
47+
@Nested
48+
class NestedTestDefaultEnclosingConfiguration {
49+
50+
@Test
51+
void annotationDefinedOnParentOfEnclosingIsInheritedByDefault(@Autowired AbstractEndpoint mockEndpoint) {
52+
assertThat(mockEndpoint.isRunning()).isFalse();
53+
}
54+
55+
}
56+
57+
@Nested
58+
@NestedTestConfiguration(NestedTestConfiguration.EnclosingConfiguration.INHERIT)
59+
class NestedTestWithInheritEnclosingConfiguration {
60+
61+
@Test
62+
void annotationDefinedOnParentOfEnclosingIsInherited(@Autowired AbstractEndpoint mockEndpoint) {
63+
assertThat(mockEndpoint.isRunning()).isFalse();
64+
}
65+
66+
}
67+
68+
@Nested
69+
@NestedTestConfiguration(NestedTestConfiguration.EnclosingConfiguration.INHERIT)
70+
@SpringIntegrationTest(noAutoStartup = "noSuchEndpointWithThisPatternExists")
71+
class NestedTestWithInheritEnclosingConfigurationButOverrideAnnotation {
72+
73+
@Test
74+
void annotationDefinedOnParentOfEnclosingIsOverridden(@Autowired AbstractEndpoint mockEndpoint) {
75+
assertThat(mockEndpoint.isRunning()).isTrue();
76+
}
77+
78+
}
79+
80+
@Nested
81+
@NestedTestConfiguration(NestedTestConfiguration.EnclosingConfiguration.OVERRIDE)
82+
@ContextConfiguration(classes = MockEndpointConfig.class)
83+
class NestedTestWithOverrideEnclosingConfiguration {
84+
85+
@Test
86+
void annotationDefinedOnParentOfEnclosingIsIgnored(@Autowired AbstractEndpoint mockEndpoint,
87+
@Nullable @Autowired MockIntegrationContext mockIntegrationContext) {
88+
89+
assertThat(mockEndpoint.isRunning()).isTrue();
90+
assertThat(mockIntegrationContext).isNull();
91+
}
92+
93+
}
94+
95+
}

src/reference/antora/modules/ROOT/pages/testing.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ The endpoints are matched to the provided patterns, which support the following
206206

207207
This is useful when we would like to not have real connections to the target systems from inbound channel adapters (for example an AMQP Inbound Gateway, JDBC Polling Channel Adapter, WebSocket Message Producer in client mode, and so on).
208208

209+
The `@SpringIntegrationTest` honors the `org.springframework.test.context.NestedTestConfiguration` semantics, hence it can be declared on the outer class (or even its super class) - and `@SpringIntegrationTest` environment will be available to inherited `@Nested` tests.
210+
209211
The `MockIntegrationContext` is meant to be used in the target test cases for modifications to beans in the real application context.
210212
For example, endpoints that have `autoStartup` overridden to `false` can be replaced with mocks, as the following example shows:
211213

0 commit comments

Comments
 (0)