Skip to content

Commit 1818161

Browse files
committed
Ensure bottom-up semantics in resolveDefaultContextConfigurationAttributes()
Closes gh-31456
1 parent 8916ee9 commit 1818161

File tree

4 files changed

+209
-2
lines changed

4 files changed

+209
-2
lines changed

spring-test/src/main/java/org/springframework/test/context/support/ContextLoaderUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ static List<ContextConfigurationAttributes> resolveDefaultContextConfigurationAt
243243
private static void resolveDefaultContextConfigurationAttributes(
244244
List<ContextConfigurationAttributes> results, Class<?> testClass) {
245245

246-
results.add(0, new ContextConfigurationAttributes(testClass));
246+
results.add(new ContextConfigurationAttributes(testClass));
247247

248248
Class<?> superclass = testClass.getSuperclass();
249249
if (superclass != null && superclass != Object.class) {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2002-present 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.test.context.config;
18+
19+
import org.junit.jupiter.api.Test;
20+
import org.junit.jupiter.api.extension.ExtendWith;
21+
22+
import org.springframework.beans.factory.annotation.Autowired;
23+
import org.springframework.context.annotation.Bean;
24+
import org.springframework.context.annotation.Configuration;
25+
import org.springframework.core.annotation.AnnotatedElementUtils;
26+
import org.springframework.test.context.ContextConfiguration;
27+
import org.springframework.test.context.junit.jupiter.SpringExtension;
28+
29+
import static org.assertj.core.api.Assertions.assertThat;
30+
31+
/**
32+
* Base tests for detection of implicit configuration classes.
33+
*
34+
* @author Sam Brannen
35+
* @since 7.0.2
36+
* @see DefaultConfigClassesBaseTests
37+
*/
38+
@ExtendWith(SpringExtension.class)
39+
class ImplicitDefaultConfigClassesBaseTests {
40+
41+
@Autowired
42+
String greeting1;
43+
44+
@Test
45+
void greeting1() {
46+
// This class must NOT be annotated with @SpringJUnitConfig or @ContextConfiguration.
47+
assertThat(AnnotatedElementUtils.hasAnnotation(getClass(), ContextConfiguration.class)).isFalse();
48+
49+
assertThat(greeting1).isEqualTo("TEST 1");
50+
}
51+
52+
@Configuration
53+
static class DefaultConfig {
54+
55+
@Bean
56+
String greeting1() {
57+
return "TEST 1";
58+
}
59+
}
60+
61+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2002-present 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.test.context.config;
18+
19+
import java.util.List;
20+
21+
import org.junit.jupiter.api.Test;
22+
23+
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.context.annotation.Bean;
25+
import org.springframework.context.annotation.Configuration;
26+
import org.springframework.core.annotation.AnnotatedElementUtils;
27+
import org.springframework.test.context.ContextConfiguration;
28+
29+
import static org.assertj.core.api.Assertions.assertThat;
30+
31+
/**
32+
* Inherited tests for detection of implicit configuration classes.
33+
*
34+
* @author Sam Brannen
35+
* @since 7.0.2
36+
* @see DefaultConfigClassesInheritedTests
37+
*/
38+
class ImplicitDefaultConfigClassesInheritedTests extends ImplicitDefaultConfigClassesBaseTests {
39+
40+
@Autowired
41+
String greeting2;
42+
43+
@Test
44+
void greeting2() {
45+
// This class must NOT be annotated with @SpringJUnitConfig or @ContextConfiguration.
46+
assertThat(AnnotatedElementUtils.hasAnnotation(getClass(), ContextConfiguration.class)).isFalse();
47+
48+
assertThat(greeting2).isEqualTo("TEST 2");
49+
}
50+
51+
@Test
52+
void greetings(@Autowired List<String> greetings) {
53+
assertThat(greetings).containsExactly("TEST 1", "TEST 2");
54+
}
55+
56+
@Configuration
57+
static class DefaultConfig {
58+
59+
@Bean
60+
String greeting2() {
61+
return "TEST 2";
62+
}
63+
}
64+
65+
}

spring-test/src/test/java/org/springframework/test/context/support/ContextLoaderUtilsConfigurationAttributesTests.java

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import static org.assertj.core.api.Assertions.assertThat;
2929
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
3030
import static org.springframework.test.context.support.ContextLoaderUtils.resolveContextConfigurationAttributes;
31+
import static org.springframework.test.context.support.ContextLoaderUtils.resolveDefaultContextConfigurationAttributes;
3132

3233
/**
3334
* Tests for {@link ContextLoaderUtils} involving {@link ContextConfigurationAttributes}.
@@ -164,8 +165,76 @@ void resolveConfigAttributesWithLocationsAndClasses() {
164165
assertThat(attributesList).hasSize(1);
165166
}
166167

168+
@Test
169+
void resolveDefaultContextConfigurationAttributesWithSuperclass() {
170+
var attributesList = resolveDefaultContextConfigurationAttributes(Superclass.class);
171+
assertThat(attributesList).hasSize(1);
172+
173+
var configAttributes = attributesList.get(0);
174+
assertThat(configAttributes.getDeclaringClass()).isEqualTo(Superclass.class);
175+
assertDefaultAttributes(configAttributes);
176+
}
177+
178+
@Test
179+
void resolveDefaultContextConfigurationAttributesWithSubclass() {
180+
var attributesList = resolveDefaultContextConfigurationAttributes(Subclass.class);
181+
assertThat(attributesList).hasSize(2);
182+
183+
// For bottom-up semantics, Subclass must come before Superclass.
184+
var configAttributes = attributesList.get(0);
185+
assertThat(configAttributes.getDeclaringClass()).isEqualTo(Subclass.class);
186+
assertDefaultAttributes(configAttributes);
187+
188+
configAttributes = attributesList.get(1);
189+
assertThat(configAttributes.getDeclaringClass()).isEqualTo(Superclass.class);
190+
assertDefaultAttributes(configAttributes);
191+
}
192+
193+
@Test
194+
void resolveDefaultContextConfigurationAttributesWithNestedClass() {
195+
var attributesList = resolveDefaultContextConfigurationAttributes(Superclass.NestedTests.class);
196+
assertThat(attributesList).hasSize(2);
197+
198+
// For bottom-up semantics, Superclass.NestedTests must come before Superclass.
199+
var configAttributes = attributesList.get(0);
200+
assertThat(configAttributes.getDeclaringClass()).isEqualTo(Superclass.NestedTests.class);
201+
assertDefaultAttributes(configAttributes);
202+
203+
configAttributes = attributesList.get(1);
204+
assertThat(configAttributes.getDeclaringClass()).isEqualTo(Superclass.class);
205+
assertDefaultAttributes(configAttributes);
206+
}
207+
208+
@Test
209+
void resolveDefaultContextConfigurationAttributesWithNestedClassesInSuperAndSubClasses() {
210+
var attributesList = resolveDefaultContextConfigurationAttributes(Subclass.NestedTests.class);
211+
assertThat(attributesList).hasSize(3);
212+
213+
// For bottom-up semantics, Subclass.NestedTests must come before Subclass.
214+
var configAttributes = attributesList.get(0);
215+
assertThat(configAttributes.getDeclaringClass()).isEqualTo(Subclass.NestedTests.class);
216+
assertDefaultAttributes(configAttributes);
217+
218+
// For bottom-up semantics, Subclass must come before Superclass.
219+
configAttributes = attributesList.get(1);
220+
assertThat(configAttributes.getDeclaringClass()).isEqualTo(Subclass.class);
221+
assertDefaultAttributes(configAttributes);
222+
223+
configAttributes = attributesList.get(2);
224+
assertThat(configAttributes.getDeclaringClass()).isEqualTo(Superclass.class);
225+
assertDefaultAttributes(configAttributes);
226+
}
227+
228+
229+
private static void assertDefaultAttributes(ContextConfigurationAttributes configAttributes) {
230+
assertThat(configAttributes.getClasses()).isEmpty();
231+
assertThat(configAttributes.getLocations()).isEmpty();
232+
assertThat(configAttributes.getInitializers()).isEmpty();
233+
assertThat(configAttributes.getContextLoaderClass()).isEqualTo(ContextLoader.class);
234+
assertThat(configAttributes.isInheritInitializers()).isTrue();
235+
assertThat(configAttributes.isInheritLocations()).isTrue();
236+
}
167237

168-
// -------------------------------------------------------------------------
169238

170239
@ContextConfiguration(value = "x", locations = "y")
171240
private static class ConflictingLocations {
@@ -175,4 +244,16 @@ private static class ConflictingLocations {
175244
private static class LocationsAndClasses {
176245
}
177246

247+
static class Superclass {
248+
// @Nested
249+
class NestedTests {
250+
}
251+
}
252+
253+
static class Subclass extends Superclass {
254+
// @Nested
255+
class NestedTests {
256+
}
257+
}
258+
178259
}

0 commit comments

Comments
 (0)