Discover test config on enclosing classes for nested test classes

Prior to this commit (and since Spring Framework 5.0), Spring's
integration with JUnit Jupiter supported detection of test
configuration (e.g., @ContextConfiguration, etc.) on @Nested classes.
However, if a @Nested class did not declare its own test configuration,
Spring would not find the configuration from the enclosing class. This
is in contrast to Spring's support for automatic inheritance of test
configuration from superclasses. The only workaround was to
copy-n-paste the entire annotation configuration from enclosing classes
to nested tests classes, which is cumbersome and error prone.

This commit introduces a new @NestedTestConfiguration annotation that
allows one to choose the EnclosingConfiguration mode that Spring should
use when searching for test configuration on a @Nested test class.
Currently, the options are INHERIT or OVERRIDE, where the current
default is OVERRIDE. Note, however, that the default mode will be
changed to INHERIT in a subsequent commit. In addition, support will be
added to configure the global default mode via the SpringProperties
mechanism in order to allow development teams to revert to the behavior
prior to Spring Framework 5.3.

As of this commit, inheritance of the following annotations is honored
when the EnclosingConfiguration mode is INHERIT.

- @ContextConfiguration / @ContextHierarchy
- @ActiveProfiles
- @TestPropertySource / @TestPropertySources
- @WebAppConfiguration
- @TestConstructor
- @BootstrapWith
- @TestExecutionListeners
- @DirtiesContext
- @Transactional
- @Rollback / @Commit

This commit does NOT include support for inheriting the following
annotations on enclosing classes.

- @Sql / @SqlConfig / @SqlGroup

In order to implement this feature, the search algorithms in
MetaAnnotationUtils (and various other spring-test internals) have been
enhanced to detect when annotations should be looked up on enclosing
classes. Other parts of the ecosystem may find the new
searchEnclosingClass() method in MetaAnnotationUtils useful to provide
similar support.

As a side effect of the changes in this commit, validation of user
configuration in repeated @TestPropertySource declarations has been
removed, but this may be reintroduced at a later date.

Closes gh-19930
This commit is contained in:
Sam Brannen
2019-05-20 18:59:07 +02:00
committed by Sam Brannen
parent b9f7b0d955
commit 6641dbc852
30 changed files with 3185 additions and 949 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@@ -18,17 +18,33 @@ package org.springframework.test.context;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.test.context.BootstrapUtilsTests.OuterClass.NestedWithInheritedBootstrapper;
import org.springframework.test.context.BootstrapUtilsTests.OuterClass.NestedWithInheritedBootstrapper.DoubleNestedWithInheritedButOverriddenBootstrapper;
import org.springframework.test.context.BootstrapUtilsTests.OuterClass.NestedWithInheritedBootstrapper.DoubleNestedWithOverriddenBootstrapper;
import org.springframework.test.context.BootstrapUtilsTests.OuterClass.NestedWithInheritedBootstrapper.DoubleNestedWithOverriddenBootstrapper.TripleNestedWithInheritedBootstrapper;
import org.springframework.test.context.BootstrapUtilsTests.OuterClass.NestedWithInheritedBootstrapper.DoubleNestedWithOverriddenBootstrapper.TripleNestedWithInheritedBootstrapperButLocalOverride;
import org.springframework.test.context.BootstrapUtilsTests.WebAppConfigClass.NestedWithInheritedWebConfig;
import org.springframework.test.context.BootstrapUtilsTests.WebAppConfigClass.NestedWithInheritedWebConfig.DoubleNestedWithImplicitlyInheritedWebConfig;
import org.springframework.test.context.BootstrapUtilsTests.WebAppConfigClass.NestedWithInheritedWebConfig.DoubleNestedWithOverriddenWebConfig;
import org.springframework.test.context.BootstrapUtilsTests.WebAppConfigClass.NestedWithInheritedWebConfig.DoubleNestedWithOverriddenWebConfig.TripleNestedWithInheritedOverriddenWebConfig;
import org.springframework.test.context.BootstrapUtilsTests.WebAppConfigClass.NestedWithInheritedWebConfig.DoubleNestedWithOverriddenWebConfig.TripleNestedWithInheritedOverriddenWebConfigAndTestInterface;
import org.springframework.test.context.support.DefaultTestContextBootstrapper;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.context.web.WebTestContextBootstrapper;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import static org.mockito.Mockito.mock;
import static org.springframework.test.context.BootstrapUtils.resolveTestContextBootstrapper;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.INHERIT;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.OVERRIDE;
/**
* Unit tests for {@link BootstrapUtils}.
@@ -65,11 +81,6 @@ class BootstrapUtilsTests {
assertBootstrapper(NonAnnotatedClass.class, DefaultTestContextBootstrapper.class);
}
@Test
void resolveTestContextBootstrapperForWebAppConfigurationAnnotatedClass() {
assertBootstrapper(WebAppConfigurationAnnotatedClass.class, WebTestContextBootstrapper.class);
}
@Test
void resolveTestContextBootstrapperWithDirectBootstrapWithAnnotation() {
assertBootstrapper(DirectBootstrapWithAnnotationClass.class, FooBootstrapper.class);
@@ -90,6 +101,37 @@ class BootstrapUtilsTests {
assertBootstrapper(DuplicateMetaAnnotatedBootstrapWithAnnotationClass.class, FooBootstrapper.class);
}
/**
* @since 5.3
*/
@ParameterizedTest(name = "{0}")
@MethodSource
void resolveTestContextBootstrapperInEnclosingClassHierarchy(String name, Class<?> testClass, Class<?> expectedBootstrapper) {
assertBootstrapper(testClass, expectedBootstrapper);
}
static Stream<Arguments> resolveTestContextBootstrapperInEnclosingClassHierarchy() {
return Stream.of(//
args(OuterClass.class, FooBootstrapper.class),//
args(NestedWithInheritedBootstrapper.class, FooBootstrapper.class),//
args(DoubleNestedWithInheritedButOverriddenBootstrapper.class, EnigmaBootstrapper.class),//
args(DoubleNestedWithOverriddenBootstrapper.class, BarBootstrapper.class),//
args(TripleNestedWithInheritedBootstrapper.class, BarBootstrapper.class),//
args(TripleNestedWithInheritedBootstrapperButLocalOverride.class, EnigmaBootstrapper.class),//
// @WebAppConfiguration and default bootstrapper
args(WebAppConfigClass.class, WebTestContextBootstrapper.class),//
args(NestedWithInheritedWebConfig.class, WebTestContextBootstrapper.class),//
args(DoubleNestedWithImplicitlyInheritedWebConfig.class, WebTestContextBootstrapper.class),//
args(DoubleNestedWithOverriddenWebConfig.class, DefaultTestContextBootstrapper.class),//
args(TripleNestedWithInheritedOverriddenWebConfig.class, WebTestContextBootstrapper.class),//
args(TripleNestedWithInheritedOverriddenWebConfigAndTestInterface.class, DefaultTestContextBootstrapper.class)//
);
}
private static Arguments args(Class<?> testClass, Class<? extends TestContextBootstrapper> expectedBootstrapper) {
return arguments(testClass.getSimpleName(), testClass, expectedBootstrapper);
}
/**
* @since 5.1
*/
@@ -153,7 +195,62 @@ class BootstrapUtilsTests {
@BootstrapWith(EnigmaBootstrapper.class)
static class LocalDeclarationAndMetaAnnotatedBootstrapWithAnnotationClass {}
@WebAppConfiguration
static class WebAppConfigurationAnnotatedClass {}
@org.springframework.test.context.web.WebAppConfiguration
static class WebAppConfigClass {
@NestedTestConfiguration(INHERIT)
class NestedWithInheritedWebConfig {
class DoubleNestedWithImplicitlyInheritedWebConfig {
}
@NestedTestConfiguration(OVERRIDE)
class DoubleNestedWithOverriddenWebConfig {
@NestedTestConfiguration(INHERIT)
@org.springframework.test.context.web.WebAppConfiguration
class TripleNestedWithInheritedOverriddenWebConfig {
}
@NestedTestConfiguration(INHERIT)
class TripleNestedWithInheritedOverriddenWebConfigAndTestInterface {
}
}
}
// Intentionally not annotated with @WebAppConfiguration to ensure that
// TripleNestedWithInheritedOverriddenWebConfigAndTestInterface is not
// considered to be annotated with @WebAppConfiguration even though the
// enclosing class for TestInterface is annotated with @WebAppConfiguration.
interface TestInterface {
}
}
@BootWithFoo
static class OuterClass {
@NestedTestConfiguration(INHERIT)
class NestedWithInheritedBootstrapper {
@NestedTestConfiguration(INHERIT)
@BootstrapWith(EnigmaBootstrapper.class)
class DoubleNestedWithInheritedButOverriddenBootstrapper {
}
@NestedTestConfiguration(OVERRIDE)
@BootWithBar
class DoubleNestedWithOverriddenBootstrapper {
@NestedTestConfiguration(INHERIT)
class TripleNestedWithInheritedBootstrapper {
}
@NestedTestConfiguration(INHERIT)
@BootstrapWith(EnigmaBootstrapper.class)
class TripleNestedWithInheritedBootstrapperButLocalOverride {
}
}
}
}
}

View File

@@ -0,0 +1,211 @@
/*
* Copyright 2002-2020 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.test.context.junit.jupiter.nested;
import java.util.List;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.NestedTestConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.test.context.junit.jupiter.nested.ActiveProfilesNestedTests.Config1;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.INHERIT;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.OVERRIDE;
/**
* Integration tests that verify support for {@code @Nested} test classes using
* {@link ActiveProfiles @ActiveProfiles} in conjunction with the
* {@link SpringExtension} in a JUnit Jupiter environment.
*
* @author Sam Brannen
* @since 5.3
*/
@SpringJUnitConfig(Config1.class)
@ActiveProfiles("1")
class ActiveProfilesNestedTests {
@Autowired
List<String> strings;
@Test
void test() {
assertThat(this.strings).containsExactlyInAnyOrder("X", "A1");
}
@Nested
@NestedTestConfiguration(INHERIT)
class InheritedConfigTests {
@Autowired
List<String> localStrings;
@Test
void test() {
assertThat(strings).containsExactlyInAnyOrder("X", "A1");
assertThat(this.localStrings).containsExactlyInAnyOrder("X", "A1");
}
}
@Nested
@SpringJUnitConfig(Config2.class)
@ActiveProfiles("2")
class ConfigOverriddenByDefaultTests {
@Autowired
List<String> localStrings;
@Test
void test() {
assertThat(strings).containsExactlyInAnyOrder("X", "A1");
assertThat(this.localStrings).containsExactlyInAnyOrder("Y", "A2");
}
}
@Nested
@NestedTestConfiguration(INHERIT)
@ContextConfiguration(classes = Config2.class)
@ActiveProfiles("2")
class InheritedAndExtendedConfigTests {
@Autowired
List<String> localStrings;
@Test
void test() {
assertThat(strings).containsExactlyInAnyOrder("X", "A1");
assertThat(this.localStrings).containsExactlyInAnyOrder("X", "A1", "Y", "A2");
}
@Nested
@NestedTestConfiguration(OVERRIDE)
@SpringJUnitConfig({ Config1.class, Config2.class, Config3.class })
@ActiveProfiles("3")
class DoubleNestedWithOverriddenConfigTests {
@Autowired
List<String> localStrings;
@Test
void test() {
assertThat(strings).containsExactlyInAnyOrder("X", "A1");
assertThat(this.localStrings).containsExactlyInAnyOrder("X", "Y", "Z", "A3");
}
@Nested
@NestedTestConfiguration(INHERIT)
@ActiveProfiles(profiles = "2", inheritProfiles = false)
class TripleNestedWithInheritedConfigButOverriddenProfilesTests {
@Autowired
List<String> localStrings;
@Test
void test() {
assertThat(strings).containsExactlyInAnyOrder("X", "A1");
assertThat(this.localStrings).containsExactlyInAnyOrder("X", "Y", "Z", "A2");
}
}
@Nested
@NestedTestConfiguration(INHERIT)
class TripleNestedWithInheritedConfigAndTestInterfaceTests implements TestInterface {
@Autowired
List<String> localStrings;
@Test
void test() {
assertThat(strings).containsExactlyInAnyOrder("X", "A1");
assertThat(this.localStrings).containsExactlyInAnyOrder("X", "Y", "Z", "A2", "A3");
}
}
}
}
// -------------------------------------------------------------------------
@Configuration
static class Config1 {
@Bean
String x() {
return "X";
}
@Bean
@Profile("1")
String a1() {
return "A1";
}
}
@Configuration
static class Config2 {
@Bean
String y() {
return "Y";
}
@Bean
@Profile("2")
String a2() {
return "A2";
}
}
@Configuration
static class Config3 {
@Bean
String z() {
return "Z";
}
@Bean
@Profile("3")
String a3() {
return "A3";
}
}
@ActiveProfiles("2")
interface TestInterface {
}
}

View File

@@ -28,7 +28,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit.SpringJUnitJupiterTestSuite;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.test.context.junit.jupiter.nested.NestedTestsWithConstructorInjectionWithSpringAndJUnitJupiterTests.TopLevelConfig;
import org.springframework.test.context.junit.jupiter.nested.ConstructorInjectionNestedTests.TopLevelConfig;
import static org.assertj.core.api.Assertions.assertThat;
@@ -43,15 +43,15 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Sam Brannen
* @since 5.0.5
* @see NestedTestsWithSpringAndJUnitJupiterTests
* @see ContextConfigurationNestedTests
* @see org.springframework.test.context.junit4.nested.NestedTestsWithSpringRulesTests
*/
@SpringJUnitConfig(TopLevelConfig.class)
class NestedTestsWithConstructorInjectionWithSpringAndJUnitJupiterTests {
class ConstructorInjectionNestedTests {
final String foo;
NestedTestsWithConstructorInjectionWithSpringAndJUnitJupiterTests(TestInfo testInfo, @Autowired String foo) {
ConstructorInjectionNestedTests(TestInfo testInfo, @Autowired String foo) {
this.foo = foo;
}

View File

@@ -0,0 +1,212 @@
/*
* Copyright 2002-2020 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.test.context.junit.jupiter.nested;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.NestedTestConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.test.context.junit.jupiter.nested.ContextConfigurationNestedTests.TopLevelConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.INHERIT;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.OVERRIDE;
/**
* Integration tests that verify support for {@code @Nested} test classes using
* {@link ContextConfiguration @ContextConfiguration} in conjunction with the
* {@link SpringExtension} in a JUnit Jupiter environment.
*
* @author Sam Brannen
* @since 5.0
* @see ConstructorInjectionNestedTests
* @see org.springframework.test.context.junit4.nested.NestedTestsWithSpringRulesTests
*/
@SpringJUnitConfig(TopLevelConfig.class)
class ContextConfigurationNestedTests {
private static final String FOO = "foo";
private static final String BAR = "bar";
private static final String BAZ = "baz";
@Autowired
String foo;
@Test
void topLevelTest() {
assertThat(foo).isEqualTo(FOO);
}
@Nested
@SpringJUnitConfig(NestedConfig.class)
class NestedTests {
@Autowired(required = false)
@Qualifier("foo")
String localFoo;
@Autowired
String bar;
@Test
void test() {
// In contrast to nested test classes running in JUnit 4, the foo
// field in the outer instance should have been injected from the
// test ApplicationContext for the outer instance.
assertThat(foo).isEqualTo(FOO);
assertThat(this.localFoo).as("foo bean should not be present").isNull();
assertThat(this.bar).isEqualTo(BAR);
}
}
@Nested
@NestedTestConfiguration(INHERIT)
class NestedTestCaseWithInheritedConfigTests {
@Autowired(required = false)
@Qualifier("foo")
String localFoo;
@Autowired
String bar;
@Test
void test() {
// Since the configuration is inherited, the foo field in the outer instance
// and the bar field in the inner instance should both have been injected
// from the test ApplicationContext for the outer instance.
assertThat(foo).isEqualTo(FOO);
assertThat(this.localFoo).isEqualTo(FOO);
assertThat(this.bar).isEqualTo(FOO);
}
@Nested
@NestedTestConfiguration(OVERRIDE)
@SpringJUnitConfig(NestedConfig.class)
class DoubleNestedWithOverriddenConfigTests {
@Autowired(required = false)
@Qualifier("foo")
String localFoo;
@Autowired
String bar;
@Test
void test() {
// In contrast to nested test classes running in JUnit 4, the foo
// field in the outer instance should have been injected from the
// test ApplicationContext for the outer instance.
assertThat(foo).isEqualTo(FOO);
assertThat(this.localFoo).as("foo bean should not be present").isNull();
assertThat(this.bar).isEqualTo(BAR);
}
@Nested
@NestedTestConfiguration(INHERIT)
class TripleNestedWithInheritedConfigTests {
@Autowired(required = false)
@Qualifier("foo")
String localFoo;
@Autowired
String bar;
@Test
void test() {
assertThat(foo).isEqualTo(FOO);
assertThat(this.localFoo).as("foo bean should not be present").isNull();
assertThat(this.bar).isEqualTo(BAR);
}
}
@Nested
@NestedTestConfiguration(INHERIT)
class TripleNestedWithInheritedConfigAndTestInterfaceTests implements TestInterface {
@Autowired(required = false)
@Qualifier("foo")
String localFoo;
@Autowired
String bar;
@Autowired
String baz;
@Test
void test() {
assertThat(foo).isEqualTo(FOO);
assertThat(this.localFoo).as("foo bean should not be present").isNull();
assertThat(this.bar).isEqualTo(BAR);
assertThat(this.baz).isEqualTo(BAZ);
}
}
}
}
// -------------------------------------------------------------------------
@Configuration
static class TopLevelConfig {
@Bean
String foo() {
return FOO;
}
}
@Configuration
static class NestedConfig {
@Bean
String bar() {
return BAR;
}
}
@Configuration
static class TestInterfaceConfig {
@Bean
String baz() {
return BAZ;
}
}
@ContextConfiguration(classes = TestInterfaceConfig.class)
interface TestInterface {
}
}

View File

@@ -0,0 +1,235 @@
/*
* Copyright 2002-2020 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.test.context.junit.jupiter.nested;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextHierarchy;
import org.springframework.test.context.NestedTestConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit.jupiter.nested.ContextHierarchyNestedTests.ParentConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.INHERIT;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.OVERRIDE;
/**
* Integration tests that verify support for {@code @Nested} test classes using
* {@link ContextHierarchy @ContextHierarchy} in conjunction with the
* {@link SpringExtension} in a JUnit Jupiter environment.
*
* @author Sam Brannen
* @since 5.3
*/
@ExtendWith(SpringExtension.class)
@ContextHierarchy(@ContextConfiguration(classes = ParentConfig.class))
class ContextHierarchyNestedTests {
private static final String FOO = "foo";
private static final String BAR = "bar";
private static final String BAZ = "baz";
private static final String QUX = "qux";
@Autowired
String foo;
@Autowired
ApplicationContext context;
@Test
void topLevelTest() {
assertThat(this.context).as("local ApplicationContext").isNotNull();
assertThat(this.context.getParent()).as("parent ApplicationContext").isNull();
assertThat(foo).isEqualTo(FOO);
}
@Nested
@ContextConfiguration(classes = NestedConfig.class)
class NestedTests {
@Autowired
String bar;
@Autowired
ApplicationContext context;
@Test
void nestedTest() throws Exception {
assertThat(this.context).as("local ApplicationContext").isNotNull();
assertThat(this.context.getParent()).as("parent ApplicationContext").isNull();
// In contrast to nested test classes running in JUnit 4, the foo
// field in the outer instance should have been injected from the
// test ApplicationContext for the outer instance.
assertThat(foo).isEqualTo(FOO);
assertThat(this.bar).isEqualTo(BAR);
}
}
@Nested
@NestedTestConfiguration(INHERIT)
@ContextConfiguration(classes = Child1Config.class)
class NestedTestCaseWithInheritedConfigTests {
@Autowired
String bar;
@Autowired
ApplicationContext context;
@Test
void nestedTest() throws Exception {
assertThat(this.context).as("local ApplicationContext").isNotNull();
assertThat(this.context.getParent()).as("parent ApplicationContext").isNotNull();
// Since the configuration is inherited, the foo field in the outer instance
// and the bar field in the inner instance should both have been injected
// from the test ApplicationContext for the outer instance.
assertThat(foo).isEqualTo(FOO);
assertThat(this.bar).isEqualTo(BAZ + 1);
assertThat(this.context.getBean("foo", String.class)).as("child foo").isEqualTo(QUX + 1);
}
@Nested
@NestedTestConfiguration(OVERRIDE)
@ContextHierarchy({
@ContextConfiguration(classes = ParentConfig.class),
@ContextConfiguration(classes = Child2Config.class)
})
class DoubleNestedTestCaseWithOverriddenConfigTests {
@Autowired
String bar;
@Autowired
ApplicationContext context;
@Test
void nestedTest() throws Exception {
assertThat(this.context).as("local ApplicationContext").isNotNull();
assertThat(this.context.getParent()).as("parent ApplicationContext").isNotNull();
assertThat(foo).isEqualTo(FOO);
assertThat(this.bar).isEqualTo(BAZ + 2);
assertThat(this.context.getBean("foo", String.class)).as("child foo").isEqualTo(QUX + 2);
}
@Nested
@NestedTestConfiguration(INHERIT)
class TripleNestedWithInheritedConfigAndTestInterfaceTests implements TestInterface {
@Autowired
@Qualifier("foo")
String localFoo;
@Autowired
String bar;
@Autowired
ApplicationContext context;
@Test
void nestedTest() throws Exception {
assertThat(this.context).as("local ApplicationContext").isNotNull();
assertThat(this.context.getParent()).as("parent ApplicationContext").isNotNull();
assertThat(this.context.getParent().getParent()).as("grandparent ApplicationContext").isNotNull();
assertThat(foo).isEqualTo(FOO);
assertThat(this.localFoo).isEqualTo("test interface");
assertThat(this.bar).isEqualTo(BAZ + 2);
assertThat(this.context.getParent().getBean("foo", String.class)).as("child foo").isEqualTo(QUX + 2);
}
}
}
}
// -------------------------------------------------------------------------
@Configuration
static class ParentConfig {
@Bean
String foo() {
return FOO;
}
}
@Configuration
static class Child1Config {
@Bean
String foo() {
return QUX + 1;
}
@Bean
String bar() {
return BAZ + 1;
}
}
@Configuration
static class Child2Config {
@Bean
String foo() {
return QUX + 2;
}
@Bean
String bar() {
return BAZ + 2;
}
}
@Configuration
static class NestedConfig {
@Bean
String bar() {
return BAR;
}
}
@Configuration
static class TestInterfaceConfig {
@Bean
String foo() {
return "test interface";
}
}
@ContextConfiguration(classes = TestInterfaceConfig.class)
interface TestInterface {
}
}

View File

@@ -1,95 +0,0 @@
/*
* Copyright 2002-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.test.context.junit.jupiter.nested;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit.SpringJUnitJupiterTestSuite;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.test.context.junit.jupiter.nested.NestedTestsWithSpringAndJUnitJupiterTests.TopLevelConfig;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests that verify support for {@code @Nested} test classes
* in conjunction with the {@link SpringExtension} in a JUnit Jupiter environment.
*
* <p>To run these tests in an IDE that does not have built-in support for the JUnit
* Platform, simply run {@link SpringJUnitJupiterTestSuite} as a JUnit 4 test.
*
* @author Sam Brannen
* @since 5.0
* @see NestedTestsWithConstructorInjectionWithSpringAndJUnitJupiterTests
* @see org.springframework.test.context.junit4.nested.NestedTestsWithSpringRulesTests
*/
@SpringJUnitConfig(TopLevelConfig.class)
class NestedTestsWithSpringAndJUnitJupiterTests {
@Autowired
String foo;
@Test
void topLevelTest() {
assertThat(foo).isEqualTo("foo");
}
@Nested
@SpringJUnitConfig(NestedConfig.class)
class NestedTests {
@Autowired
String bar;
@Test
void nestedTest() throws Exception {
// In contrast to nested test classes running in JUnit 4, the foo
// field in the outer instance should have been injected from the
// test ApplicationContext for the outer instance.
assertThat(foo).isEqualTo("foo");
assertThat(bar).isEqualTo("bar");
}
}
// -------------------------------------------------------------------------
@Configuration
static class TopLevelConfig {
@Bean
String foo() {
return "foo";
}
}
@Configuration
static class NestedConfig {
@Bean
String bar() {
return "bar";
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@@ -45,7 +45,7 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringJUnitConfig(PopulatedSchemaDatabaseConfig.class)
@Transactional
@TestInstance(Lifecycle.PER_CLASS)
class NestedTestsWithSqlScriptsAndJUnitJupiterTests {
class SqlScriptNestedTests {
@Autowired
JdbcTemplate jdbcTemplate;
@@ -67,6 +67,10 @@ class NestedTestsWithSqlScriptsAndJUnitJupiterTests {
}
@Nested
// NOTE: the following @SpringJUnitConfig declaration must NOT be removed.
// This was added before the TestContext framework looked up configuration
// on enclosing classes for @Nested test classes. As such, this serves as a
// regression test and cannot be changed.
@SpringJUnitConfig(PopulatedSchemaDatabaseConfig.class)
@Transactional
class NestedTests {

View File

@@ -0,0 +1,169 @@
/*
* Copyright 2002-2020 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.test.context.junit.jupiter.nested;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.NestedTestConfiguration;
import org.springframework.test.context.TestConstructor;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.INHERIT;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.OVERRIDE;
import static org.springframework.test.context.TestConstructor.AutowireMode.ALL;
import static org.springframework.test.context.TestConstructor.AutowireMode.ANNOTATED;
/**
* Integration tests that verify support for {@code @Nested} test classes using
* {@link TestConstructor @TestConstructor} in conjunction with the
* {@link SpringExtension} in a JUnit Jupiter environment.
*
* @author Sam Brannen
* @since 5.3
*/
@SpringJUnitConfig
@TestConstructor(autowireMode = ALL)
class TestConstructorNestedTests {
TestConstructorNestedTests(String text) {
assertThat(text).isEqualTo("enigma");
}
@Test
void test() {
}
@Nested
@SpringJUnitConfig(Config.class)
@TestConstructor(autowireMode = ANNOTATED)
class ConfigOverriddenByDefaultTests {
@Autowired
ConfigOverriddenByDefaultTests(String text) {
assertThat(text).isEqualTo("enigma");
}
@Test
void test() {
}
}
@Nested
@NestedTestConfiguration(INHERIT)
class InheritedConfigTests {
InheritedConfigTests(String text) {
assertThat(text).isEqualTo("enigma");
}
@Test
void test() {
}
@Nested
class DoubleNestedWithImplicitlyInheritedConfigTests {
DoubleNestedWithImplicitlyInheritedConfigTests(String text) {
assertThat(text).isEqualTo("enigma");
}
@Test
void test() {
}
@Nested
class TripleNestedWithImplicitlyInheritedConfigTests {
TripleNestedWithImplicitlyInheritedConfigTests(String text) {
assertThat(text).isEqualTo("enigma");
}
@Test
void test() {
}
}
}
@Nested
@NestedTestConfiguration(OVERRIDE)
@SpringJUnitConfig(Config.class)
@TestConstructor(autowireMode = ANNOTATED)
class DoubleNestedWithOverriddenConfigTests {
DoubleNestedWithOverriddenConfigTests(@Autowired String text) {
assertThat(text).isEqualTo("enigma");
}
@Test
void test() {
}
@Nested
@NestedTestConfiguration(INHERIT)
class TripleNestedWithInheritedConfigTests {
@Autowired
TripleNestedWithInheritedConfigTests(String text) {
assertThat(text).isEqualTo("enigma");
}
@Test
void test() {
}
}
@Nested
@NestedTestConfiguration(INHERIT)
class TripleNestedWithInheritedConfigAndTestInterfaceTests implements TestInterface {
TripleNestedWithInheritedConfigAndTestInterfaceTests(String text) {
assertThat(text).isEqualTo("enigma");
}
@Test
void test() {
}
}
}
}
// -------------------------------------------------------------------------
@Configuration
static class Config {
@Bean
String text() {
return "enigma";
}
}
@TestConstructor(autowireMode = ALL)
interface TestInterface {
}
}

View File

@@ -0,0 +1,192 @@
/*
* Copyright 2002-2020 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.test.context.junit.jupiter.nested;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.NestedTestConfiguration;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.test.context.junit.jupiter.nested.TestExecutionListenersNestedTests.FooTestExecutionListener;
import org.springframework.test.context.support.AbstractTestExecutionListener;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.INHERIT;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.OVERRIDE;
/**
* Integration tests that verify support for {@code @Nested} test classes using
* {@link TestExecutionListeners @TestExecutionListeners} in conjunction with the
* {@link SpringExtension} in a JUnit Jupiter environment.
*
* @author Sam Brannen
* @since 5.3
*/
@SpringJUnitConfig
@TestExecutionListeners(FooTestExecutionListener.class)
class TestExecutionListenersNestedTests {
private static final String FOO = "foo";
private static final String BAR = "bar";
private static final String BAZ = "baz";
private static final String QUX = "qux";
private static final List<String> listeners = new ArrayList<>();
@AfterEach
void resetListeners() {
listeners.clear();
}
@Test
void test() {
assertThat(listeners).containsExactly(FOO);
}
@Nested
@NestedTestConfiguration(INHERIT)
class InheritedConfigTests {
@Test
void test() {
assertThat(listeners).containsExactly(FOO);
}
}
@Nested
@SpringJUnitConfig(Config.class)
@TestExecutionListeners(BarTestExecutionListener.class)
class ConfigOverriddenByDefaultTests {
@Test
void test() {
assertThat(listeners).containsExactly(BAR);
}
}
@Nested
@NestedTestConfiguration(INHERIT)
@SpringJUnitConfig(Config.class)
@TestExecutionListeners(BarTestExecutionListener.class)
class InheritedAndExtendedConfigTests {
@Test
void test() {
assertThat(listeners).containsExactly(FOO, BAR);
}
@Nested
@NestedTestConfiguration(OVERRIDE)
@SpringJUnitConfig(Config.class)
@TestExecutionListeners(BazTestExecutionListener.class)
class DoubleNestedWithOverriddenConfigTests {
@Test
void test() {
assertThat(listeners).containsExactly(BAZ);
}
@Nested
@NestedTestConfiguration(INHERIT)
@TestExecutionListeners(listeners = BarTestExecutionListener.class, inheritListeners = false)
class TripleNestedWithInheritedConfigButOverriddenListenersTests {
@Test
void test() {
assertThat(listeners).containsExactly(BAR);
}
}
@Nested
@NestedTestConfiguration(INHERIT)
class TripleNestedWithInheritedConfigAndTestInterfaceTests implements TestInterface {
@Test
void test() {
assertThat(listeners).containsExactly(BAZ, QUX);
}
}
}
}
// -------------------------------------------------------------------------
@Configuration
static class Config {
/* no user beans required for these tests */
}
private static abstract class BaseTestExecutionListener extends AbstractTestExecutionListener {
protected abstract String name();
@Override
public final void beforeTestClass(TestContext testContext) {
listeners.add(name());
}
}
static class FooTestExecutionListener extends BaseTestExecutionListener {
@Override
protected String name() {
return FOO;
}
}
static class BarTestExecutionListener extends BaseTestExecutionListener {
@Override
protected String name() {
return BAR;
}
}
static class BazTestExecutionListener extends BaseTestExecutionListener {
@Override
protected String name() {
return BAZ;
}
}
static class QuxTestExecutionListener extends BaseTestExecutionListener {
@Override
protected String name() {
return QUX;
}
}
@TestExecutionListeners(QuxTestExecutionListener.class)
interface TestInterface {
}
}

View File

@@ -0,0 +1,195 @@
/*
* Copyright 2002-2020 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.test.context.junit.jupiter.nested;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.test.context.NestedTestConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.test.context.junit.jupiter.nested.TestPropertySourceNestedTests.Config;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.INHERIT;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.OVERRIDE;
/**
* Integration tests that verify support for {@code @Nested} test classes using
* {@link TestPropertySource @TestPropertySource} in conjunction with the
* {@link SpringExtension} in a JUnit Jupiter environment.
*
* @author Sam Brannen
* @since 5.3
*/
@SpringJUnitConfig(Config.class)
@TestPropertySource(properties = "p1 = v1")
class TestPropertySourceNestedTests {
@Autowired
Environment env1;
@Test
void propertiesInEnvironment() {
assertThat(env1.getProperty("p1")).isEqualTo("v1");
}
@Nested
@NestedTestConfiguration(INHERIT)
class InheritedConfigTests {
@Autowired
Environment env2;
@Test
void propertiesInEnvironment() {
assertThat(env1.getProperty("p1")).isEqualTo("v1");
assertThat(env2.getProperty("p1")).isEqualTo("v1");
assertThat(env1).isSameAs(env2);
}
}
@Nested
@SpringJUnitConfig(Config.class)
@TestPropertySource(properties = "p2 = v2")
class ConfigOverriddenByDefaultTests {
@Autowired
Environment env2;
@Test
void propertiesInEnvironment() {
assertThat(env1.getProperty("p1")).isEqualTo("v1");
assertThat(env1).isNotSameAs(env2);
assertThat(env2.getProperty("p1")).isNull();
assertThat(env2.getProperty("p2")).isEqualTo("v2");
}
}
@Nested
@NestedTestConfiguration(INHERIT)
@TestPropertySource(properties = "p2a = v2a")
@TestPropertySource(properties = "p2b = v2b")
class InheritedAndExtendedConfigTests {
@Autowired
Environment env2;
@Test
void propertiesInEnvironment() {
assertThat(env1.getProperty("p1")).isEqualTo("v1");
assertThat(env1).isNotSameAs(env2);
assertThat(env2.getProperty("p1")).isEqualTo("v1");
assertThat(env2.getProperty("p2a")).isEqualTo("v2a");
assertThat(env2.getProperty("p2b")).isEqualTo("v2b");
}
@Nested
@NestedTestConfiguration(OVERRIDE)
@SpringJUnitConfig(Config.class)
@TestPropertySource(properties = "p3 = v3")
class L3WithOverriddenConfigTests {
@Autowired
Environment env3;
@Test
void propertiesInEnvironment() {
assertThat(env1.getProperty("p1")).isEqualTo("v1");
assertThat(env1).isNotSameAs(env2);
assertThat(env2.getProperty("p1")).isEqualTo("v1");
assertThat(env2.getProperty("p2a")).isEqualTo("v2a");
assertThat(env2.getProperty("p2b")).isEqualTo("v2b");
assertThat(env2).isNotSameAs(env3);
assertThat(env3.getProperty("p1")).isNull();
assertThat(env3.getProperty("p2")).isNull();
assertThat(env3.getProperty("p3")).isEqualTo("v3");
}
@Nested
@NestedTestConfiguration(INHERIT)
@TestPropertySource(properties = {"p3 = v34", "p4 = v4"}, inheritProperties = false)
class L4WithInheritedConfigButOverriddenTestPropertiesTests {
@Autowired
Environment env4;
@Test
void propertiesInEnvironment() {
assertThat(env1.getProperty("p1")).isEqualTo("v1");
assertThat(env1).isNotSameAs(env2);
assertThat(env2.getProperty("p1")).isEqualTo("v1");
assertThat(env2.getProperty("p2a")).isEqualTo("v2a");
assertThat(env2.getProperty("p2b")).isEqualTo("v2b");
assertThat(env2).isNotSameAs(env3);
assertThat(env3.getProperty("p1")).isNull();
assertThat(env3.getProperty("p2")).isNull();
assertThat(env3.getProperty("p3")).isEqualTo("v3");
assertThat(env3).isNotSameAs(env4);
assertThat(env4.getProperty("p1")).isNull();
assertThat(env4.getProperty("p2")).isNull();
assertThat(env4.getProperty("p3")).isEqualTo("v34");
assertThat(env4.getProperty("p4")).isEqualTo("v4");
}
@Nested
class L5WithInheritedConfigAndTestInterfaceTests implements TestInterface {
@Autowired
Environment env5;
@Test
void propertiesInEnvironment() {
assertThat(env4).isNotSameAs(env5);
assertThat(env5.getProperty("foo")).isEqualTo("bar");
assertThat(env5.getProperty("enigma")).isEqualTo("42");
assertThat(env5.getProperty("p1")).isNull();
assertThat(env5.getProperty("p2")).isNull();
assertThat(env5.getProperty("p3")).isEqualTo("v34");
assertThat(env5.getProperty("p4")).isEqualTo("v4");
}
}
}
}
}
// -------------------------------------------------------------------------
@Configuration
static class Config {
/* no user beans required for these tests */
}
@TestPropertySource(properties = { "foo = bar", "enigma: 42" })
interface TestInterface {
}
}

View File

@@ -0,0 +1,185 @@
/*
* Copyright 2002-2020 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.test.context.junit.jupiter.nested;
import javax.sql.DataSource;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.test.annotation.Commit;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.NestedTestConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.test.context.transaction.TestTransaction;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.INHERIT;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.OVERRIDE;
import static org.springframework.test.transaction.TransactionAssert.assertThatTransaction;
import static org.springframework.transaction.annotation.Propagation.NOT_SUPPORTED;
/**
* Integration tests that verify support for {@code @Nested} test classes using
* {@link Transactional @Transactional} in conjunction with the
* {@link SpringExtension} in a JUnit Jupiter environment.
*
* @author Sam Brannen
* @since 5.3
*/
@SpringJUnitConfig
@Transactional
@Commit
class TransactionalNestedTests {
@Test
void transactional(@Autowired DataSource dataSource) {
assertThatTransaction().isActive();
assertThat(dataSource).isNotNull();
assertCommit();
}
@Nested
@SpringJUnitConfig(Config.class)
class ConfigOverriddenByDefaultTests {
@Test
void notTransactional(@Autowired DataSource dataSource) {
assertThatTransaction().isNotActive();
assertThat(dataSource).isNotNull();
}
}
@Nested
@NestedTestConfiguration(INHERIT)
class InheritedConfigTests {
@Test
void transactional(@Autowired DataSource dataSource) {
assertThatTransaction().isActive();
assertThat(dataSource).isNotNull();
assertCommit();
}
@Nested
class DoubleNestedWithImplicitlyInheritedConfigTests {
@Test
void transactional(@Autowired DataSource dataSource) {
assertThatTransaction().isActive();
assertThat(dataSource).isNotNull();
assertCommit();
}
@Nested
@Rollback
class TripleNestedWithImplicitlyInheritedConfigTests {
@Test
void transactional(@Autowired DataSource dataSource) {
assertThatTransaction().isActive();
assertThat(dataSource).isNotNull();
assertRollback();
}
}
}
@Nested
@NestedTestConfiguration(OVERRIDE)
@SpringJUnitConfig(Config.class)
@Transactional
@Rollback
class DoubleNestedWithOverriddenConfigTests {
@Test
void transactional(@Autowired DataSource dataSource) {
assertThatTransaction().isActive();
assertThat(dataSource).isNotNull();
assertRollback();
}
@Nested
@NestedTestConfiguration(INHERIT)
@Commit
class TripleNestedWithInheritedConfigTests {
@Test
void transactional(@Autowired DataSource dataSource) {
assertThatTransaction().isActive();
assertThat(dataSource).isNotNull();
assertCommit();
}
}
@Nested
@NestedTestConfiguration(INHERIT)
class TripleNestedWithInheritedConfigAndTestInterfaceTests implements TestInterface {
@Test
void notTransactional(@Autowired DataSource dataSource) {
assertThatTransaction().isNotActive();
assertThat(dataSource).isNotNull();
}
}
}
}
private void assertCommit() {
assertThat(TestTransaction.isFlaggedForRollback()).as("flagged for commit").isFalse();
}
private void assertRollback() {
assertThat(TestTransaction.isFlaggedForRollback()).as("flagged for rollback").isTrue();
}
// -------------------------------------------------------------------------
@Configuration
@EnableTransactionManagement
static class Config {
@Bean
TransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
DataSource dataSource() {
return new EmbeddedDatabaseBuilder().generateUniqueName(true).build();
}
}
@Transactional(propagation = NOT_SUPPORTED)
interface TestInterface {
}
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright 2002-2020 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.test.context.junit.jupiter.nested;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.NestedTestConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.test.context.junit.jupiter.nested.WebAppConfigurationNestedTests.Config;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.context.WebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.INHERIT;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.OVERRIDE;
/**
* Integration tests that verify support for {@code @Nested} test classes using
* {@link WebAppConfiguration @WebAppConfiguration} in conjunction with the
* {@link SpringExtension} in a JUnit Jupiter environment.
*
* @author Sam Brannen
* @since 5.0
* @see ConstructorInjectionNestedTests
* @see org.springframework.test.context.junit4.nested.NestedTestsWithSpringRulesTests
*/
@SpringJUnitWebConfig(Config.class)
class WebAppConfigurationNestedTests {
@Test
void test(ApplicationContext context) {
assertThat(context).isInstanceOf(WebApplicationContext.class);
}
@Nested
@SpringJUnitConfig(Config.class)
class ConfigOverriddenByDefaultTests {
@Test
void test(ApplicationContext context) {
assertThat(context).isNotInstanceOf(WebApplicationContext.class);
}
}
@Nested
@SpringJUnitWebConfig(Config.class)
class ConfigOverriddenByDefaultWebTests {
@Test
void test(ApplicationContext context) {
assertThat(context).isInstanceOf(WebApplicationContext.class);
}
}
@Nested
@NestedTestConfiguration(INHERIT)
class NestedWithInheritedConfigTests {
@Test
void test(ApplicationContext context) {
assertThat(context).isInstanceOf(WebApplicationContext.class);
}
@Nested
class DoubleNestedWithImplicitlyInheritedConfigWebTests {
@Test
void test(ApplicationContext context) {
assertThat(context).isInstanceOf(WebApplicationContext.class);
}
}
@Nested
@NestedTestConfiguration(OVERRIDE)
@SpringJUnitConfig(Config.class)
class DoubleNestedWithOverriddenConfigWebTests {
@Test
void test(ApplicationContext context) {
assertThat(context).isNotInstanceOf(WebApplicationContext.class);
}
@Nested
@NestedTestConfiguration(INHERIT)
class TripleNestedWithInheritedConfigWebTests {
@Test
void test(ApplicationContext context) {
assertThat(context).isNotInstanceOf(WebApplicationContext.class);
}
}
@Nested
@NestedTestConfiguration(INHERIT)
class TripleNestedWithInheritedConfigAndTestInterfaceTests implements TestInterface {
@Test
void test(ApplicationContext context) {
assertThat(context).isInstanceOf(WebApplicationContext.class);
}
}
}
}
// -------------------------------------------------------------------------
@Configuration
static class Config {
}
@WebAppConfiguration
interface TestInterface {
}
}

View File

@@ -33,12 +33,16 @@ import org.springframework.test.context.BootstrapTestUtils;
import org.springframework.test.context.CacheAwareContextLoaderDelegate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextHierarchy;
import org.springframework.test.context.ContextLoader;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.NestedTestConfiguration;
import org.springframework.test.context.TestContextBootstrapper;
import org.springframework.test.context.web.WebAppConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.SoftAssertions.assertSoftly;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.INHERIT;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.OVERRIDE;
/**
* Abstract base class for tests involving {@link ContextLoaderUtils},
@@ -68,11 +72,13 @@ abstract class AbstractContextConfigurationUtilsTests {
String[] expectedLocations, Class<?>[] expectedClasses,
Class<? extends ContextLoader> expectedContextLoaderClass, boolean expectedInheritLocations) {
assertThat(attributes.getDeclaringClass()).as("declaring class").isEqualTo(expectedDeclaringClass);
assertThat(attributes.getLocations()).as("locations").isEqualTo(expectedLocations);
assertThat(attributes.getClasses()).as("classes").isEqualTo(expectedClasses);
assertThat(attributes.isInheritLocations()).as("inherit locations").isEqualTo(expectedInheritLocations);
assertThat(attributes.getContextLoaderClass()).as("context loader").isEqualTo(expectedContextLoaderClass);
assertSoftly(softly -> {
softly.assertThat(attributes.getDeclaringClass()).as("declaring class").isEqualTo(expectedDeclaringClass);
softly.assertThat(attributes.getLocations()).as("locations").isEqualTo(expectedLocations);
softly.assertThat(attributes.getClasses()).as("classes").isEqualTo(expectedClasses);
softly.assertThat(attributes.isInheritLocations()).as("inherit locations").isEqualTo(expectedInheritLocations);
softly.assertThat(attributes.getContextLoaderClass()).as("context loader").isEqualTo(expectedContextLoaderClass);
});
}
void assertMergedConfig(MergedContextConfiguration mergedConfig, Class<?> expectedTestClass,
@@ -91,21 +97,22 @@ abstract class AbstractContextConfigurationUtilsTests {
Set<Class<? extends ApplicationContextInitializer<?>>> expectedInitializerClasses,
Class<? extends ContextLoader> expectedContextLoaderClass) {
assertThat(mergedConfig).isNotNull();
assertThat(mergedConfig.getTestClass()).isEqualTo(expectedTestClass);
assertThat(mergedConfig.getLocations()).isNotNull();
assertThat(mergedConfig.getLocations()).isEqualTo(expectedLocations);
assertThat(mergedConfig.getClasses()).isNotNull();
assertThat(mergedConfig.getClasses()).isEqualTo(expectedClasses);
assertThat(mergedConfig.getActiveProfiles()).isNotNull();
if (expectedContextLoaderClass == null) {
assertThat(mergedConfig.getContextLoader()).isNull();
}
else {
assertThat(mergedConfig.getContextLoader().getClass()).isEqualTo(expectedContextLoaderClass);
}
assertThat(mergedConfig.getContextInitializerClasses()).isNotNull();
assertThat(mergedConfig.getContextInitializerClasses()).isEqualTo(expectedInitializerClasses);
assertSoftly(softly -> {
softly.assertThat(mergedConfig).as("merged config").isNotNull();
softly.assertThat(mergedConfig.getTestClass()).as("test class").isEqualTo(expectedTestClass);
softly.assertThat(mergedConfig.getLocations()).as("locations").containsExactly(expectedLocations);
softly.assertThat(mergedConfig.getClasses()).as("classes").containsExactly(expectedClasses);
softly.assertThat(mergedConfig.getActiveProfiles()).as("active profiles").isNotNull();
if (expectedContextLoaderClass == null) {
softly.assertThat(mergedConfig.getContextLoader()).as("context loader").isNull();
}
else {
softly.assertThat(mergedConfig.getContextLoader().getClass()).as("context loader").isEqualTo(expectedContextLoaderClass);
}
softly.assertThat(mergedConfig.getContextInitializerClasses()).as("context initializers").isNotNull();
softly.assertThat(mergedConfig.getContextInitializerClasses()).as("context initializers").isEqualTo(expectedInitializerClasses);
});
}
@SafeVarargs
@@ -130,6 +137,14 @@ abstract class AbstractContextConfigurationUtilsTests {
static class BarConfig {
}
@Configuration
static class BazConfig {
}
@Configuration
static class QuuxConfig {
}
@ContextConfiguration("/foo.xml")
@ActiveProfiles(profiles = "foo")
@Retention(RetentionPolicy.RUNTIME)
@@ -219,4 +234,46 @@ abstract class AbstractContextConfigurationUtilsTests {
static class PropertiesClassesFoo {
}
@ContextConfiguration(classes = FooConfig.class, loader = AnnotationConfigContextLoader.class)
@NestedTestConfiguration(INHERIT)
static class OuterTestCase {
class NestedTestCaseWithInheritedConfig {
}
@ContextConfiguration(classes = BarConfig.class)
class NestedTestCaseWithMergedInheritedConfig {
}
@NestedTestConfiguration(OVERRIDE)
@ContextConfiguration(classes = BarConfig.class)
class NestedTestCaseWithOverriddenConfig {
@NestedTestConfiguration(INHERIT)
class DoubleNestedTestCaseWithInheritedOverriddenConfig {
}
}
}
@ContextHierarchy({ //
@ContextConfiguration(classes = FooConfig.class, loader = AnnotationConfigContextLoader.class, name = "foo"), //
@ContextConfiguration(classes = BarConfig.class, loader = AnnotationConfigContextLoader.class, name = "bar")//
})
@NestedTestConfiguration(INHERIT)
static class ContextHierarchyOuterTestCase {
class NestedTestCaseWithInheritedConfig {
}
@ContextConfiguration(classes = BazConfig.class, loader = AnnotationConfigContextLoader.class, name = "bar")
class NestedTestCaseWithMergedInheritedConfig {
}
@ContextConfiguration(classes = QuuxConfig.class, loader = AnnotationConfigContextLoader.class, name = "foo", inheritLocations = false)
class NestedTestCaseWithOverriddenConfig {
}
}
}

View File

@@ -21,6 +21,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.assertj.core.api.AssertionsForClassTypes;
import org.junit.jupiter.api.Test;
import org.springframework.test.context.BootstrapTestUtils;
@@ -220,6 +221,137 @@ class BootstrapTestUtilsMergedConfigTests extends AbstractContextConfigurationUt
assertThat(mergedConfig.getPropertySourceProperties()).isEmpty();
}
/**
* @since 5.3
*/
@Test
public void buildMergedConfigForNestedTestClassWithInheritedConfig() {
Class<?> testClass = OuterTestCase.NestedTestCaseWithInheritedConfig.class;
Class<?>[] expectedClasses = array(FooConfig.class);
MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass);
assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, expectedClasses,
AnnotationConfigContextLoader.class);
}
/**
* @since 5.3
*/
@Test
public void buildMergedConfigForNestedTestClassWithMergedInheritedConfig() {
Class<?> testClass = OuterTestCase.NestedTestCaseWithMergedInheritedConfig.class;
Class<?>[] expectedClasses = array(FooConfig.class, BarConfig.class);
MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass);
assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, expectedClasses,
AnnotationConfigContextLoader.class);
}
/**
* @since 5.3
*/
@Test
public void buildMergedConfigForNestedTestClassWithOverriddenConfig() {
Class<?> testClass = OuterTestCase.NestedTestCaseWithOverriddenConfig.class;
Class<?>[] expectedClasses = array(BarConfig.class);
MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass);
assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, expectedClasses,
DelegatingSmartContextLoader.class);
}
/**
* @since 5.3
*/
@Test
public void buildMergedConfigForDoubleNestedTestClassWithInheritedOverriddenConfig() {
Class<?> testClass = OuterTestCase.NestedTestCaseWithOverriddenConfig.DoubleNestedTestCaseWithInheritedOverriddenConfig.class;
Class<?>[] expectedClasses = array(BarConfig.class);
MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass);
assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, expectedClasses,
DelegatingSmartContextLoader.class);
}
/**
* @since 5.3
*/
@Test
public void buildMergedConfigForContextHierarchy() {
Class<?> testClass = ContextHierarchyOuterTestCase.class;
Class<?>[] expectedClasses = array(BarConfig.class);
MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass);
assertThat(mergedConfig).as("merged config").isNotNull();
MergedContextConfiguration parent = mergedConfig.getParent();
assertThat(parent).as("parent config").isNotNull();
// The following does not work -- at least not in Eclipse.
// asssertThat(parent.getClasses())...
// So we use AssertionsForClassTypes directly.
AssertionsForClassTypes.assertThat(parent.getClasses()).containsExactly(FooConfig.class);
assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, expectedClasses,
AnnotationConfigContextLoader.class);
}
/**
* @since 5.3
*/
@Test
public void buildMergedConfigForNestedTestClassWithInheritedConfigForContextHierarchy() {
Class<?> enclosingTestClass = ContextHierarchyOuterTestCase.class;
Class<?> testClass = ContextHierarchyOuterTestCase.NestedTestCaseWithInheritedConfig.class;
Class<?>[] expectedClasses = array(BarConfig.class);
MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass);
assertThat(mergedConfig).as("merged config").isNotNull();
MergedContextConfiguration parent = mergedConfig.getParent();
assertThat(parent).as("parent config").isNotNull();
AssertionsForClassTypes.assertThat(parent.getClasses()).containsExactly(FooConfig.class);
assertMergedConfig(mergedConfig, enclosingTestClass, EMPTY_STRING_ARRAY, expectedClasses,
AnnotationConfigContextLoader.class);
}
/**
* @since 5.3
*/
@Test
public void buildMergedConfigForNestedTestClassWithMergedInheritedConfigForContextHierarchy() {
Class<?> testClass = ContextHierarchyOuterTestCase.NestedTestCaseWithMergedInheritedConfig.class;
Class<?>[] expectedClasses = array(BarConfig.class, BazConfig.class);
MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass);
assertThat(mergedConfig).as("merged config").isNotNull();
MergedContextConfiguration parent = mergedConfig.getParent();
assertThat(parent).as("parent config").isNotNull();
AssertionsForClassTypes.assertThat(parent.getClasses()).containsExactly(FooConfig.class);
assertMergedConfig(mergedConfig, testClass, EMPTY_STRING_ARRAY, expectedClasses,
AnnotationConfigContextLoader.class);
}
/**
* @since 5.3
*/
@Test
public void buildMergedConfigForNestedTestClassWithOverriddenConfigForContextHierarchy() {
Class<?> testClass = ContextHierarchyOuterTestCase.NestedTestCaseWithOverriddenConfig.class;
MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass);
assertThat(mergedConfig).as("merged config").isNotNull();
MergedContextConfiguration parent = mergedConfig.getParent();
assertThat(parent).as("parent config").isNotNull();
assertMergedConfig(parent, testClass, EMPTY_STRING_ARRAY, array(QuuxConfig.class),
AnnotationConfigContextLoader.class);
assertMergedConfig(mergedConfig, ContextHierarchyOuterTestCase.class, EMPTY_STRING_ARRAY,
array(BarConfig.class), AnnotationConfigContextLoader.class);
}
@ContextConfiguration
@Retention(RetentionPolicy.RUNTIME)

View File

@@ -19,12 +19,15 @@ package org.springframework.test.context.support;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.BDDMockito;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.DirtiesContext.HierarchyMode;
import org.springframework.test.context.NestedTestConfiguration;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestExecutionListener;
@@ -40,6 +43,8 @@ import static org.springframework.test.annotation.DirtiesContext.ClassMode.BEFOR
import static org.springframework.test.annotation.DirtiesContext.HierarchyMode.CURRENT_LEVEL;
import static org.springframework.test.annotation.DirtiesContext.HierarchyMode.EXHAUSTIVE;
import static org.springframework.test.annotation.DirtiesContext.MethodMode.BEFORE_METHOD;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.INHERIT;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.OVERRIDE;
/**
* Unit tests for {@link DirtiesContextBeforeModesTestExecutionListener}.
@@ -48,6 +53,7 @@ import static org.springframework.test.annotation.DirtiesContext.MethodMode.BEFO
* @author Sam Brannen
* @since 4.0
*/
@DisplayName("@DirtiesContext TestExecutionListener tests")
class DirtiesContextTestExecutionListenerTests {
private final TestExecutionListener beforeListener = new DirtiesContextBeforeModesTestExecutionListener();
@@ -55,12 +61,261 @@ class DirtiesContextTestExecutionListenerTests {
private final TestContext testContext = mock(TestContext.class);
@Test
void beforeAndAfterTestMethodForDirtiesContextDeclaredLocallyOnMethodWithBeforeMethodMode() throws Exception {
Class<?> clazz = getClass();
@Nested
@DisplayName("Before and after test method")
class BeforeAndAfterTestMethodTests {
@Test
void declaredLocallyOnMethodWithBeforeMethodMode() throws Exception {
Class<?> clazz = getClass().getEnclosingClass();
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(
clazz.getDeclaredMethod("dirtiesContextDeclaredLocallyWithBeforeMethodMode"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
afterListener.afterTestMethod(testContext);
beforeListener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
void declaredLocallyOnMethodWithAfterMethodMode() throws Exception {
Class<?> clazz = getClass().getEnclosingClass();
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(
clazz.getDeclaredMethod("dirtiesContextDeclaredLocallyWithAfterMethodMode"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
afterListener.afterTestMethod(testContext);
beforeListener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
void declaredOnMethodViaMetaAnnotationWithAfterMethodMode() throws Exception {
Class<?> clazz = getClass().getEnclosingClass();
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(
clazz.getDeclaredMethod("dirtiesContextDeclaredViaMetaAnnotationWithAfterMethodMode"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
afterListener.afterTestMethod(testContext);
beforeListener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
void declaredLocallyOnClassBeforeEachTestMethod() throws Exception {
assertBeforeMethod(DirtiesContextDeclaredLocallyBeforeEachTestMethod.class);
}
@Test
void declaredLocallyOnClassAfterEachTestMethod() throws Exception {
assertAfterMethod(DirtiesContextDeclaredLocallyAfterEachTestMethod.class);
}
@Test
void declaredViaMetaAnnotationOnClassAfterEachTestMethod() throws Exception {
assertAfterMethod(DirtiesContextDeclaredViaMetaAnnotationAfterEachTestMethod.class);
}
@Test
void declaredLocallyOnClassBeforeClass() throws Exception {
Class<?> clazz = DirtiesContextDeclaredLocallyBeforeClass.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("test"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
afterListener.afterTestMethod(testContext);
beforeListener.afterTestMethod(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
void declaredLocallyOnClassAfterClass() throws Exception {
Class<?> clazz = DirtiesContextDeclaredLocallyAfterClass.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("test"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
afterListener.afterTestMethod(testContext);
beforeListener.afterTestMethod(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
void declaredViaMetaAnnotationOnClassAfterClass() throws Exception {
Class<?> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterClass.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("test"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
afterListener.afterTestMethod(testContext);
beforeListener.afterTestMethod(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
void beforeAndAfterTestMethodForDirtiesContextViaMetaAnnotationWithOverrides() throws Exception {
Class<?> clazz = DirtiesContextViaMetaAnnotationWithOverrides.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("test"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
afterListener.afterTestMethod(testContext);
beforeListener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(CURRENT_LEVEL);
}
}
@Nested
@DisplayName("Before and after test class")
class BeforeAndAfterTestClassTests {
@Test
void declaredLocallyOnMethod() throws Exception {
Class<?> clazz = getClass().getEnclosingClass();
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
beforeListener.beforeTestClass(testContext);
afterListener.beforeTestClass(testContext);
afterListener.afterTestClass(testContext);
beforeListener.afterTestClass(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
void declaredLocallyOnClassBeforeEachTestMethod() throws Exception {
Class<?> clazz = DirtiesContextDeclaredLocallyBeforeEachTestMethod.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
beforeListener.beforeTestClass(testContext);
afterListener.beforeTestClass(testContext);
afterListener.afterTestClass(testContext);
beforeListener.afterTestClass(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
void declaredLocallyOnClassAfterEachTestMethod() throws Exception {
Class<?> clazz = DirtiesContextDeclaredLocallyAfterEachTestMethod.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
beforeListener.beforeTestClass(testContext);
afterListener.beforeTestClass(testContext);
afterListener.afterTestClass(testContext);
beforeListener.afterTestClass(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
void declaredViaMetaAnnotationOnClassAfterEachTestMethod() throws Exception {
Class<?> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterEachTestMethod.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
beforeListener.beforeTestClass(testContext);
afterListener.beforeTestClass(testContext);
afterListener.afterTestClass(testContext);
beforeListener.afterTestClass(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
void declaredLocallyOnClassBeforeClass() throws Exception {
assertBeforeClass(DirtiesContextDeclaredLocallyBeforeClass.class);
}
@Test
void declaredLocallyOnClassAfterClass() throws Exception {
assertAfterClass(DirtiesContextDeclaredLocallyAfterClass.class);
}
@Test
void declaredViaMetaAnnotationOnClassAfterClass() throws Exception {
assertAfterClass(DirtiesContextDeclaredViaMetaAnnotationAfterClass.class);
}
@Test
void declaredViaMetaAnnotationWithOverrides() throws Exception {
Class<?> clazz = DirtiesContextViaMetaAnnotationWithOverrides.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
beforeListener.beforeTestClass(testContext);
afterListener.beforeTestClass(testContext);
afterListener.afterTestClass(testContext);
beforeListener.afterTestClass(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
void declaredViaMetaAnnotationWithOverriddenAttributes() throws Exception {
assertAfterClass(DirtiesContextViaMetaAnnotationWithOverridenAttributes.class);
}
}
@Nested
@DisplayName("Nested config - before and after test method modes")
class NestedBeforeAndAfterTestMethodTests {
@Test
void onTopLevelClassWithBeforeEachTestMethod() throws Exception {
assertBeforeMethod(BeforeAndAfterTestMethodTopLevelClass.class);
}
@Test
void onNestedClassWithConfigOverriddenByDefaultWithAfterClass() throws Exception {
assertAfterMethod(BeforeAndAfterTestMethodTopLevelClass.ConfigOverriddenByDefault.class);
}
@Test
void onNestedClassWithInheritedConfigWithBeforeEachTestMethod() throws Exception {
assertBeforeMethod(BeforeAndAfterTestMethodTopLevelClass.InheritedConfig.class);
}
@Test
void onNestedClassWithOverriddenConfigWithAfterClass() throws Exception {
assertAfterMethod(BeforeAndAfterTestMethodTopLevelClass.OverriddenConfig.class);
}
@Test
void onNestedClassWithInheritedConfigButOverriddenWithBeforeEachTestMethod() throws Exception {
assertBeforeMethod(BeforeAndAfterTestMethodTopLevelClass.OverriddenConfig.InheritedConfigButOverridden.class);
}
}
@Nested
@DisplayName("Nested config - before and after test class modes")
class NestedBeforeAndAfterTestClassTests {
@Test
void onTopLevelClassWithBeforeClass() throws Exception {
assertBeforeClass(BeforeAndAfterTestClassTopLevelClass.class);
}
@Test
void onNestedClassWithConfigOverriddenByDefaultWithAfterClass() throws Exception {
assertAfterClass(BeforeAndAfterTestClassTopLevelClass.ConfigOverriddenByDefault.class);
}
@Test
void onNestedClassWithInheritedConfigWithBeforeClass() throws Exception {
assertBeforeClass(BeforeAndAfterTestClassTopLevelClass.InheritedConfig.class);
}
@Test
void onNestedClassWithOverriddenConfigWithAfterClass() throws Exception {
assertAfterClass(BeforeAndAfterTestClassTopLevelClass.OverriddenConfig.class);
}
@Test
void onNestedClassWithInheritedConfigButOverriddenWithBeforeClass() throws Exception {
assertBeforeClass(BeforeAndAfterTestClassTopLevelClass.OverriddenConfig.InheritedConfigButOverridden.class);
}
}
private void assertBeforeMethod(Class<?> clazz) throws Exception {
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(
clazz.getDeclaredMethod("dirtiesContextDeclaredLocallyWithBeforeMethodMode"));
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("test"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
@@ -69,12 +324,9 @@ class DirtiesContextTestExecutionListenerTests {
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
void beforeAndAfterTestMethodForDirtiesContextDeclaredLocallyOnMethodWithAfterMethodMode() throws Exception {
Class<?> clazz = getClass();
private void assertAfterMethod(Class<?> clazz) throws NoSuchMethodException, Exception {
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(
clazz.getDeclaredMethod("dirtiesContextDeclaredLocallyWithAfterMethodMode"));
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("test"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
@@ -83,160 +335,7 @@ class DirtiesContextTestExecutionListenerTests {
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
void beforeAndAfterTestMethodForDirtiesContextDeclaredOnMethodViaMetaAnnotationWithAfterMethodMode()
throws Exception {
Class<?> clazz = getClass();
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(
clazz.getDeclaredMethod("dirtiesContextDeclaredViaMetaAnnotationWithAfterMethodMode"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
afterListener.afterTestMethod(testContext);
beforeListener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
void beforeAndAfterTestMethodForDirtiesContextDeclaredLocallyOnClassBeforeEachTestMethod() throws Exception {
Class<?> clazz = DirtiesContextDeclaredLocallyBeforeEachTestMethod.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("clean"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
afterListener.afterTestMethod(testContext);
beforeListener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
void beforeAndAfterTestMethodForDirtiesContextDeclaredLocallyOnClassAfterEachTestMethod() throws Exception {
Class<?> clazz = DirtiesContextDeclaredLocallyAfterEachTestMethod.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("clean"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
afterListener.afterTestMethod(testContext);
beforeListener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
void beforeAndAfterTestMethodForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterEachTestMethod()
throws Exception {
Class<?> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterEachTestMethod.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("clean"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
afterListener.afterTestMethod(testContext);
beforeListener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
void beforeAndAfterTestMethodForDirtiesContextDeclaredLocallyOnClassBeforeClass() throws Exception {
Class<?> clazz = DirtiesContextDeclaredLocallyBeforeClass.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("clean"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
afterListener.afterTestMethod(testContext);
beforeListener.afterTestMethod(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
void beforeAndAfterTestMethodForDirtiesContextDeclaredLocallyOnClassAfterClass() throws Exception {
Class<?> clazz = DirtiesContextDeclaredLocallyAfterClass.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("clean"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
afterListener.afterTestMethod(testContext);
beforeListener.afterTestMethod(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
void beforeAndAfterTestMethodForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterClass() throws Exception {
Class<?> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterClass.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("clean"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
afterListener.afterTestMethod(testContext);
beforeListener.afterTestMethod(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
void beforeAndAfterTestMethodForDirtiesContextViaMetaAnnotationWithOverrides() throws Exception {
Class<?> clazz = DirtiesContextViaMetaAnnotationWithOverrides.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("clean"));
beforeListener.beforeTestMethod(testContext);
afterListener.beforeTestMethod(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
afterListener.afterTestMethod(testContext);
beforeListener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(CURRENT_LEVEL);
}
// -------------------------------------------------------------------------
@Test
void beforeAndAfterTestClassForDirtiesContextDeclaredLocallyOnMethod() throws Exception {
Class<?> clazz = getClass();
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
beforeListener.beforeTestClass(testContext);
afterListener.beforeTestClass(testContext);
afterListener.afterTestClass(testContext);
beforeListener.afterTestClass(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
void beforeAndAfterTestClassForDirtiesContextDeclaredLocallyOnClassBeforeEachTestMethod() throws Exception {
Class<?> clazz = DirtiesContextDeclaredLocallyBeforeEachTestMethod.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
beforeListener.beforeTestClass(testContext);
afterListener.beforeTestClass(testContext);
afterListener.afterTestClass(testContext);
beforeListener.afterTestClass(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
void beforeAndAfterTestClassForDirtiesContextDeclaredLocallyOnClassAfterEachTestMethod() throws Exception {
Class<?> clazz = DirtiesContextDeclaredLocallyAfterEachTestMethod.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
beforeListener.beforeTestClass(testContext);
afterListener.beforeTestClass(testContext);
afterListener.afterTestClass(testContext);
beforeListener.afterTestClass(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
void beforeAndAfterTestClassForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterEachTestMethod()
throws Exception {
Class<?> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterEachTestMethod.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
beforeListener.beforeTestClass(testContext);
afterListener.beforeTestClass(testContext);
afterListener.afterTestClass(testContext);
beforeListener.afterTestClass(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
void beforeAndAfterTestClassForDirtiesContextDeclaredLocallyOnClassBeforeClass() throws Exception {
Class<?> clazz = DirtiesContextDeclaredLocallyBeforeClass.class;
private void assertBeforeClass(Class<?> clazz) throws Exception {
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
beforeListener.beforeTestClass(testContext);
afterListener.beforeTestClass(testContext);
@@ -246,45 +345,7 @@ class DirtiesContextTestExecutionListenerTests {
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
void beforeAndAfterTestClassForDirtiesContextDeclaredLocallyOnClassAfterClass() throws Exception {
Class<?> clazz = DirtiesContextDeclaredLocallyAfterClass.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
beforeListener.beforeTestClass(testContext);
afterListener.beforeTestClass(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
afterListener.afterTestClass(testContext);
beforeListener.afterTestClass(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
void beforeAndAfterTestClassForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterClass() throws Exception {
Class<?> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterClass.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
beforeListener.beforeTestClass(testContext);
afterListener.beforeTestClass(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
afterListener.afterTestClass(testContext);
beforeListener.afterTestClass(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
void beforeAndAfterTestClassForDirtiesContextDeclaredViaMetaAnnotationWithOverrides() throws Exception {
Class<?> clazz = DirtiesContextViaMetaAnnotationWithOverrides.class;
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
beforeListener.beforeTestClass(testContext);
afterListener.beforeTestClass(testContext);
afterListener.afterTestClass(testContext);
beforeListener.afterTestClass(testContext);
verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
void beforeAndAfterTestClassForDirtiesContextDeclaredViaMetaAnnotationWithOverriddenAttributes()
throws Exception {
Class<?> clazz = DirtiesContextViaMetaAnnotationWithOverridenAttributes.class;
private void assertAfterClass(Class<?> clazz) throws Exception {
BDDMockito.<Class<?>> given(testContext.getTestClass()).willReturn(clazz);
beforeListener.beforeTestClass(testContext);
afterListener.beforeTestClass(testContext);
@@ -298,54 +359,49 @@ class DirtiesContextTestExecutionListenerTests {
@DirtiesContext(methodMode = BEFORE_METHOD)
void dirtiesContextDeclaredLocallyWithBeforeMethodMode() {
/* no-op */
}
@DirtiesContext
void dirtiesContextDeclaredLocallyWithAfterMethodMode() {
/* no-op */
}
@MetaDirtyAfterMethod
void dirtiesContextDeclaredViaMetaAnnotationWithAfterMethodMode() {
/* no-op */
}
@DirtiesContext
@Retention(RetentionPolicy.RUNTIME)
static @interface MetaDirtyAfterMethod {
@interface MetaDirtyAfterMethod {
}
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)
@Retention(RetentionPolicy.RUNTIME)
static @interface MetaDirtyAfterEachTestMethod {
@interface MetaDirtyAfterEachTestMethod {
}
@DirtiesContext(classMode = AFTER_CLASS)
@Retention(RetentionPolicy.RUNTIME)
static @interface MetaDirtyAfterClass {
@interface MetaDirtyAfterClass {
}
@DirtiesContext(classMode = BEFORE_EACH_TEST_METHOD)
static class DirtiesContextDeclaredLocallyBeforeEachTestMethod {
void clean() {
/* no-op */
void test() {
}
}
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)
static class DirtiesContextDeclaredLocallyAfterEachTestMethod {
void clean() {
/* no-op */
void test() {
}
}
@DirtiesContext
@Retention(RetentionPolicy.RUNTIME)
static @interface MetaDirtyWithOverrides {
@interface MetaDirtyWithOverrides {
ClassMode classMode() default AFTER_EACH_TEST_METHOD;
@@ -355,48 +411,116 @@ class DirtiesContextTestExecutionListenerTests {
@MetaDirtyAfterEachTestMethod
static class DirtiesContextDeclaredViaMetaAnnotationAfterEachTestMethod {
void clean() {
/* no-op */
void test() {
}
}
@DirtiesContext(classMode = BEFORE_CLASS)
static class DirtiesContextDeclaredLocallyBeforeClass {
void clean() {
/* no-op */
void test() {
}
}
@DirtiesContext(classMode = AFTER_CLASS)
static class DirtiesContextDeclaredLocallyAfterClass {
void clean() {
/* no-op */
void test() {
}
}
@MetaDirtyAfterClass
static class DirtiesContextDeclaredViaMetaAnnotationAfterClass {
void clean() {
/* no-op */
void test() {
}
}
@MetaDirtyWithOverrides
static class DirtiesContextViaMetaAnnotationWithOverrides {
void clean() {
/* no-op */
void test() {
}
}
@MetaDirtyWithOverrides(classMode = AFTER_CLASS, hierarchyMode = EXHAUSTIVE)
static class DirtiesContextViaMetaAnnotationWithOverridenAttributes {
void clean() {
/* no-op */
void test() {
}
}
@DirtiesContext(classMode = BEFORE_CLASS)
static class BeforeAndAfterTestClassTopLevelClass {
void test() {
}
@DirtiesContext(classMode = AFTER_CLASS)
class ConfigOverriddenByDefault {
void test() {
}
}
@NestedTestConfiguration(INHERIT)
class InheritedConfig {
void test() {
}
}
@NestedTestConfiguration(OVERRIDE)
@DirtiesContext(classMode = AFTER_CLASS)
class OverriddenConfig {
@NestedTestConfiguration(INHERIT)
@DirtiesContext(classMode = BEFORE_CLASS)
class InheritedConfigButOverridden {
void test() {
}
}
}
}
@DirtiesContext(classMode = BEFORE_EACH_TEST_METHOD)
static class BeforeAndAfterTestMethodTopLevelClass {
void test() {
}
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)
class ConfigOverriddenByDefault {
void test() {
}
}
@NestedTestConfiguration(INHERIT)
class InheritedConfig {
void test() {
}
}
@NestedTestConfiguration(OVERRIDE)
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)
class OverriddenConfig {
void test() {
}
@NestedTestConfiguration(INHERIT)
@DirtiesContext(classMode = BEFORE_EACH_TEST_METHOD)
class InheritedConfigButOverridden {
void test() {
}
}
}
}

View File

@@ -20,6 +20,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Map;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.context.ConfigurableApplicationContext;
@@ -80,6 +81,7 @@ class TestPropertySourceUtilsTests {
}
@Test
@Disabled("Validation for repeated @TestPropertySource annotations has been removed")
void repeatedTestPropertySourcesWithConflictingInheritLocationsFlags() {
assertThatIllegalArgumentException()
.isThrownBy(() -> buildMergedTestPropertySources(RepeatedPropertySourcesWithConflictingInheritLocationsFlags.class))
@@ -89,6 +91,7 @@ class TestPropertySourceUtilsTests {
}
@Test
@Disabled("Validation for repeated @TestPropertySource annotations has been removed")
void repeatedTestPropertySourcesWithConflictingInheritPropertiesFlags() {
assertThatIllegalArgumentException()
.isThrownBy(() -> buildMergedTestPropertySources(RepeatedPropertySourcesWithConflictingInheritPropertiesFlags.class))

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@@ -17,12 +17,13 @@
package org.springframework.test.util;
import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.core.annotation.AnnotationUtils;
@@ -47,489 +48,489 @@ import static org.springframework.test.util.MetaAnnotationUtils.findAnnotationDe
*/
class MetaAnnotationUtilsTests {
private void assertAtComponentOnComposedAnnotation(
Class<?> rootDeclaringClass, String name, Class<? extends Annotation> composedAnnotationType) {
@Nested
@DisplayName("findAnnotationDescriptor() tests")
class FindAnnotationDescriptorTests {
assertAtComponentOnComposedAnnotation(rootDeclaringClass, rootDeclaringClass, name, composedAnnotationType);
}
@Test
void findAnnotationDescriptorWithNoAnnotationPresent() {
assertThat(findAnnotationDescriptor(NonAnnotatedInterface.class, Transactional.class)).isNull();
assertThat(findAnnotationDescriptor(NonAnnotatedClass.class, Transactional.class)).isNull();
}
private void assertAtComponentOnComposedAnnotation(
Class<?> startClass, Class<?> rootDeclaringClass, String name, Class<? extends Annotation> composedAnnotationType) {
@Test
void findAnnotationDescriptorWithInheritedAnnotationOnClass() {
// Note: @Transactional is inherited
assertThat(findAnnotationDescriptor(InheritedAnnotationClass.class, Transactional.class).getRootDeclaringClass()).isEqualTo(InheritedAnnotationClass.class);
assertThat(findAnnotationDescriptor(SubInheritedAnnotationClass.class, Transactional.class).getRootDeclaringClass()).isEqualTo(InheritedAnnotationClass.class);
}
assertAtComponentOnComposedAnnotation(startClass, rootDeclaringClass, composedAnnotationType, name, composedAnnotationType);
}
@Test
void findAnnotationDescriptorWithInheritedAnnotationOnInterface() {
// Note: @Transactional is inherited
Transactional rawAnnotation = InheritedAnnotationInterface.class.getAnnotation(Transactional.class);
AnnotationDescriptor<Transactional> descriptor =
findAnnotationDescriptor(InheritedAnnotationInterface.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(InheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(InheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
private void assertAtComponentOnComposedAnnotation(Class<?> startClass, Class<?> rootDeclaringClass,
Class<?> declaringClass, String name, Class<? extends Annotation> composedAnnotationType) {
descriptor = findAnnotationDescriptor(SubInheritedAnnotationInterface.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(SubInheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(InheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
AnnotationDescriptor<Component> descriptor = findAnnotationDescriptor(startClass, Component.class);
assertThat(descriptor).as("AnnotationDescriptor should not be null").isNotNull();
assertThat(descriptor.getRootDeclaringClass()).as("rootDeclaringClass").isEqualTo(rootDeclaringClass);
assertThat(descriptor.getDeclaringClass()).as("declaringClass").isEqualTo(declaringClass);
assertThat(descriptor.getAnnotationType()).as("annotationType").isEqualTo(Component.class);
assertThat(descriptor.getAnnotation().value()).as("component name").isEqualTo(name);
assertThat(descriptor.getComposedAnnotation()).as("composedAnnotation should not be null").isNotNull();
assertThat(descriptor.getComposedAnnotationType()).as("composedAnnotationType").isEqualTo(composedAnnotationType);
}
descriptor = findAnnotationDescriptor(SubSubInheritedAnnotationInterface.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(SubSubInheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(InheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
}
private void assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(
Class<?> startClass, String name, Class<? extends Annotation> composedAnnotationType) {
@Test
void findAnnotationDescriptorForNonInheritedAnnotationOnClass() {
// Note: @Order is not inherited.
assertThat(findAnnotationDescriptor(NonInheritedAnnotationClass.class, Order.class).getRootDeclaringClass()).isEqualTo(NonInheritedAnnotationClass.class);
assertThat(findAnnotationDescriptor(SubNonInheritedAnnotationClass.class, Order.class).getRootDeclaringClass()).isEqualTo(NonInheritedAnnotationClass.class);
}
assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(
startClass, startClass, name, composedAnnotationType);
}
@Test
void findAnnotationDescriptorForNonInheritedAnnotationOnInterface() {
// Note: @Order is not inherited.
Order rawAnnotation = NonInheritedAnnotationInterface.class.getAnnotation(Order.class);
private void assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(Class<?> startClass,
Class<?> rootDeclaringClass, String name, Class<? extends Annotation> composedAnnotationType) {
AnnotationDescriptor<Order> descriptor =
findAnnotationDescriptor(NonInheritedAnnotationInterface.class, Order.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(NonInheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(NonInheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(
startClass, rootDeclaringClass, composedAnnotationType, name, composedAnnotationType);
}
descriptor = findAnnotationDescriptor(SubNonInheritedAnnotationInterface.class, Order.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(SubNonInheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(NonInheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
}
@SuppressWarnings("unchecked")
private void assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(Class<?> startClass,
Class<?> rootDeclaringClass, Class<?> declaringClass, String name,
Class<? extends Annotation> composedAnnotationType) {
@Test
void findAnnotationDescriptorWithMetaComponentAnnotation() {
assertAtComponentOnComposedAnnotation(HasMetaComponentAnnotation.class, "meta1", Meta1.class);
}
Class<Component> annotationType = Component.class;
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(
startClass, Service.class, annotationType, Order.class, Transactional.class);
assertThat(descriptor).as("UntypedAnnotationDescriptor should not be null").isNotNull();
assertThat(descriptor.getRootDeclaringClass()).as("rootDeclaringClass").isEqualTo(rootDeclaringClass);
assertThat(descriptor.getDeclaringClass()).as("declaringClass").isEqualTo(declaringClass);
assertThat(descriptor.getAnnotationType()).as("annotationType").isEqualTo(annotationType);
assertThat(((Component) descriptor.getAnnotation()).value()).as("component name").isEqualTo(name);
assertThat(descriptor.getComposedAnnotation()).as("composedAnnotation should not be null").isNotNull();
assertThat(descriptor.getComposedAnnotationType()).as("composedAnnotationType").isEqualTo(composedAnnotationType);
}
@Test
void findAnnotationDescriptorWithNoAnnotationPresent() {
assertThat(findAnnotationDescriptor(NonAnnotatedInterface.class, Transactional.class)).isNull();
assertThat(findAnnotationDescriptor(NonAnnotatedClass.class, Transactional.class)).isNull();
}
@Test
void findAnnotationDescriptorWithInheritedAnnotationOnClass() {
// Note: @Transactional is inherited
assertThat(findAnnotationDescriptor(InheritedAnnotationClass.class, Transactional.class).getRootDeclaringClass()).isEqualTo(InheritedAnnotationClass.class);
assertThat(findAnnotationDescriptor(SubInheritedAnnotationClass.class, Transactional.class).getRootDeclaringClass()).isEqualTo(InheritedAnnotationClass.class);
}
@Test
void findAnnotationDescriptorWithInheritedAnnotationOnInterface() {
// Note: @Transactional is inherited
Transactional rawAnnotation = InheritedAnnotationInterface.class.getAnnotation(Transactional.class);
AnnotationDescriptor<Transactional> descriptor =
findAnnotationDescriptor(InheritedAnnotationInterface.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(InheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(InheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
descriptor = findAnnotationDescriptor(SubInheritedAnnotationInterface.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(SubInheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(InheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
descriptor = findAnnotationDescriptor(SubSubInheritedAnnotationInterface.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(SubSubInheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(InheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
}
@Test
void findAnnotationDescriptorForNonInheritedAnnotationOnClass() {
// Note: @Order is not inherited.
assertThat(findAnnotationDescriptor(NonInheritedAnnotationClass.class, Order.class).getRootDeclaringClass()).isEqualTo(NonInheritedAnnotationClass.class);
assertThat(findAnnotationDescriptor(SubNonInheritedAnnotationClass.class, Order.class).getRootDeclaringClass()).isEqualTo(NonInheritedAnnotationClass.class);
}
@Test
void findAnnotationDescriptorForNonInheritedAnnotationOnInterface() {
// Note: @Order is not inherited.
Order rawAnnotation = NonInheritedAnnotationInterface.class.getAnnotation(Order.class);
AnnotationDescriptor<Order> descriptor =
findAnnotationDescriptor(NonInheritedAnnotationInterface.class, Order.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(NonInheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(NonInheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
descriptor = findAnnotationDescriptor(SubNonInheritedAnnotationInterface.class, Order.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(SubNonInheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(NonInheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
}
@Test
void findAnnotationDescriptorWithMetaComponentAnnotation() {
assertAtComponentOnComposedAnnotation(HasMetaComponentAnnotation.class, "meta1", Meta1.class);
}
@Test
void findAnnotationDescriptorWithLocalAndMetaComponentAnnotation() {
Class<Component> annotationType = Component.class;
AnnotationDescriptor<Component> descriptor = findAnnotationDescriptor(
@Test
void findAnnotationDescriptorWithLocalAndMetaComponentAnnotation() {
Class<Component> annotationType = Component.class;
AnnotationDescriptor<Component> descriptor = findAnnotationDescriptor(
HasLocalAndMetaComponentAnnotation.class, annotationType);
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(HasLocalAndMetaComponentAnnotation.class);
assertThat(descriptor.getAnnotationType()).isEqualTo(annotationType);
assertThat(descriptor.getComposedAnnotation()).isNull();
assertThat(descriptor.getComposedAnnotationType()).isNull();
}
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(HasLocalAndMetaComponentAnnotation.class);
assertThat(descriptor.getAnnotationType()).isEqualTo(annotationType);
assertThat(descriptor.getComposedAnnotation()).isNull();
assertThat(descriptor.getComposedAnnotationType()).isNull();
}
@Test
void findAnnotationDescriptorForInterfaceWithMetaAnnotation() {
assertAtComponentOnComposedAnnotation(InterfaceWithMetaAnnotation.class, "meta1", Meta1.class);
}
@Test
void findAnnotationDescriptorForInterfaceWithMetaAnnotation() {
assertAtComponentOnComposedAnnotation(InterfaceWithMetaAnnotation.class, "meta1", Meta1.class);
}
@Test
void findAnnotationDescriptorForClassWithMetaAnnotatedInterface() {
Component rawAnnotation = AnnotationUtils.findAnnotation(ClassWithMetaAnnotatedInterface.class, Component.class);
AnnotationDescriptor<Component> descriptor =
findAnnotationDescriptor(ClassWithMetaAnnotatedInterface.class, Component.class);
@Test
void findAnnotationDescriptorForClassWithMetaAnnotatedInterface() {
Component rawAnnotation = AnnotationUtils.findAnnotation(ClassWithMetaAnnotatedInterface.class, Component.class);
AnnotationDescriptor<Component> descriptor =
findAnnotationDescriptor(ClassWithMetaAnnotatedInterface.class, Component.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(ClassWithMetaAnnotatedInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(Meta1.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
assertThat(descriptor.getComposedAnnotation().annotationType()).isEqualTo(Meta1.class);
}
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(ClassWithMetaAnnotatedInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(Meta1.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
assertThat(descriptor.getComposedAnnotation().annotationType()).isEqualTo(Meta1.class);
}
@Test
void findAnnotationDescriptorForClassWithLocalMetaAnnotationAndAnnotatedSuperclass() {
AnnotationDescriptor<ContextConfiguration> descriptor = findAnnotationDescriptor(
@Test
void findAnnotationDescriptorForClassWithLocalMetaAnnotationAndAnnotatedSuperclass() {
AnnotationDescriptor<ContextConfiguration> descriptor = findAnnotationDescriptor(
MetaAnnotatedAndSuperAnnotatedContextConfigClass.class, ContextConfiguration.class);
assertThat(descriptor).as("AnnotationDescriptor should not be null").isNotNull();
assertThat(descriptor.getRootDeclaringClass()).as("rootDeclaringClass").isEqualTo(MetaAnnotatedAndSuperAnnotatedContextConfigClass.class);
assertThat(descriptor.getDeclaringClass()).as("declaringClass").isEqualTo(MetaConfig.class);
assertThat(descriptor.getAnnotationType()).as("annotationType").isEqualTo(ContextConfiguration.class);
assertThat(descriptor.getComposedAnnotation()).as("composedAnnotation should not be null").isNotNull();
assertThat(descriptor.getComposedAnnotationType()).as("composedAnnotationType").isEqualTo(MetaConfig.class);
assertThat(descriptor).as("AnnotationDescriptor should not be null").isNotNull();
assertThat(descriptor.getRootDeclaringClass()).as("rootDeclaringClass").isEqualTo(MetaAnnotatedAndSuperAnnotatedContextConfigClass.class);
assertThat(descriptor.getDeclaringClass()).as("declaringClass").isEqualTo(MetaConfig.class);
assertThat(descriptor.getAnnotationType()).as("annotationType").isEqualTo(ContextConfiguration.class);
assertThat(descriptor.getComposedAnnotation()).as("composedAnnotation should not be null").isNotNull();
assertThat(descriptor.getComposedAnnotationType()).as("composedAnnotationType").isEqualTo(MetaConfig.class);
assertThat(descriptor.getAnnotationAttributes().getClassArray("classes")).as("configured classes").isEqualTo(new Class<?>[] {String.class});
}
assertThat(descriptor.getAnnotationAttributes().getClassArray("classes")).as("configured classes").isEqualTo(new Class<?>[] {String.class});
}
@Test
void findAnnotationDescriptorForClassWithLocalMetaAnnotationAndMetaAnnotatedInterface() {
assertAtComponentOnComposedAnnotation(ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class, "meta2", Meta2.class);
}
@Test
void findAnnotationDescriptorForClassWithLocalMetaAnnotationAndMetaAnnotatedInterface() {
assertAtComponentOnComposedAnnotation(ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class, "meta2", Meta2.class);
}
@Test
void findAnnotationDescriptorForSubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface() {
assertAtComponentOnComposedAnnotation(SubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class,
@Test
void findAnnotationDescriptorForSubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface() {
assertAtComponentOnComposedAnnotation(SubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class,
ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class, "meta2", Meta2.class);
}
}
/**
* @since 4.0.3
*/
@Test
void findAnnotationDescriptorOnMetaMetaAnnotatedClass() {
Class<MetaMetaAnnotatedClass> startClass = MetaMetaAnnotatedClass.class;
assertAtComponentOnComposedAnnotation(startClass, startClass, Meta2.class, "meta2", MetaMeta.class);
}
/**
* @since 4.0.3
*/
@Test
void findAnnotationDescriptorOnMetaMetaAnnotatedClass() {
Class<MetaMetaAnnotatedClass> startClass = MetaMetaAnnotatedClass.class;
assertAtComponentOnComposedAnnotation(startClass, startClass, Meta2.class, "meta2", MetaMeta.class);
}
/**
* @since 4.0.3
*/
@Test
void findAnnotationDescriptorOnMetaMetaMetaAnnotatedClass() {
Class<MetaMetaMetaAnnotatedClass> startClass = MetaMetaMetaAnnotatedClass.class;
assertAtComponentOnComposedAnnotation(startClass, startClass, Meta2.class, "meta2", MetaMetaMeta.class);
}
/**
* @since 4.0.3
*/
@Test
void findAnnotationDescriptorOnMetaMetaMetaAnnotatedClass() {
Class<MetaMetaMetaAnnotatedClass> startClass = MetaMetaMetaAnnotatedClass.class;
assertAtComponentOnComposedAnnotation(startClass, startClass, Meta2.class, "meta2", MetaMetaMeta.class);
}
/**
* @since 4.0.3
*/
@Test
void findAnnotationDescriptorOnAnnotatedClassWithMissingTargetMetaAnnotation() {
// InheritedAnnotationClass is NOT annotated or meta-annotated with @Component
AnnotationDescriptor<Component> descriptor = findAnnotationDescriptor(
/**
* @since 4.0.3
*/
@Test
void findAnnotationDescriptorOnAnnotatedClassWithMissingTargetMetaAnnotation() {
// InheritedAnnotationClass is NOT annotated or meta-annotated with @Component
AnnotationDescriptor<Component> descriptor = findAnnotationDescriptor(
InheritedAnnotationClass.class, Component.class);
assertThat(descriptor).as("Should not find @Component on InheritedAnnotationClass").isNull();
}
assertThat(descriptor).as("Should not find @Component on InheritedAnnotationClass").isNull();
}
/**
* @since 4.0.3
*/
@Test
void findAnnotationDescriptorOnMetaCycleAnnotatedClassWithMissingTargetMetaAnnotation() {
AnnotationDescriptor<Component> descriptor = findAnnotationDescriptor(
/**
* @since 4.0.3
*/
@Test
void findAnnotationDescriptorOnMetaCycleAnnotatedClassWithMissingTargetMetaAnnotation() {
AnnotationDescriptor<Component> descriptor = findAnnotationDescriptor(
MetaCycleAnnotatedClass.class, Component.class);
assertThat(descriptor).as("Should not find @Component on MetaCycleAnnotatedClass").isNull();
assertThat(descriptor).as("Should not find @Component on MetaCycleAnnotatedClass").isNull();
}
private void assertAtComponentOnComposedAnnotation(
Class<?> rootDeclaringClass, String name, Class<? extends Annotation> composedAnnotationType) {
assertAtComponentOnComposedAnnotation(rootDeclaringClass, rootDeclaringClass, name, composedAnnotationType);
}
private void assertAtComponentOnComposedAnnotation(
Class<?> startClass, Class<?> rootDeclaringClass, String name, Class<? extends Annotation> composedAnnotationType) {
assertAtComponentOnComposedAnnotation(startClass, rootDeclaringClass, composedAnnotationType, name, composedAnnotationType);
}
private void assertAtComponentOnComposedAnnotation(Class<?> startClass, Class<?> rootDeclaringClass,
Class<?> declaringClass, String name, Class<? extends Annotation> composedAnnotationType) {
AnnotationDescriptor<Component> descriptor = findAnnotationDescriptor(startClass, Component.class);
assertThat(descriptor).as("AnnotationDescriptor should not be null").isNotNull();
assertThat(descriptor.getRootDeclaringClass()).as("rootDeclaringClass").isEqualTo(rootDeclaringClass);
assertThat(descriptor.getDeclaringClass()).as("declaringClass").isEqualTo(declaringClass);
assertThat(descriptor.getAnnotationType()).as("annotationType").isEqualTo(Component.class);
assertThat(descriptor.getAnnotation().value()).as("component name").isEqualTo(name);
assertThat(descriptor.getComposedAnnotation()).as("composedAnnotation should not be null").isNotNull();
assertThat(descriptor.getComposedAnnotationType()).as("composedAnnotationType").isEqualTo(composedAnnotationType);
}
}
// -------------------------------------------------------------------------
@Nested
@DisplayName("findAnnotationDescriptorForTypes() tests")
class FindAnnotationDescriptorForTypesTests {
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesWithNoAnnotationPresent() {
assertThat(findAnnotationDescriptorForTypes(NonAnnotatedInterface.class, Transactional.class, Component.class)).isNull();
assertThat(findAnnotationDescriptorForTypes(NonAnnotatedClass.class, Transactional.class, Order.class)).isNull();
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesWithInheritedAnnotationOnClass() {
// Note: @Transactional is inherited
assertThat(findAnnotationDescriptorForTypes(InheritedAnnotationClass.class, Transactional.class).getRootDeclaringClass()).isEqualTo(InheritedAnnotationClass.class);
assertThat(findAnnotationDescriptorForTypes(SubInheritedAnnotationClass.class, Transactional.class).getRootDeclaringClass()).isEqualTo(InheritedAnnotationClass.class);
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesWithInheritedAnnotationOnInterface() {
// Note: @Transactional is inherited
Transactional rawAnnotation = InheritedAnnotationInterface.class.getAnnotation(Transactional.class);
UntypedAnnotationDescriptor descriptor =
findAnnotationDescriptorForTypes(InheritedAnnotationInterface.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(InheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(InheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
descriptor = findAnnotationDescriptorForTypes(SubInheritedAnnotationInterface.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(SubInheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(InheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
descriptor = findAnnotationDescriptorForTypes(SubSubInheritedAnnotationInterface.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(SubSubInheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(InheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesForNonInheritedAnnotationOnClass() {
// Note: @Order is not inherited.
assertThat(findAnnotationDescriptorForTypes(NonInheritedAnnotationClass.class, Order.class).getRootDeclaringClass()).isEqualTo(NonInheritedAnnotationClass.class);
assertThat(findAnnotationDescriptorForTypes(SubNonInheritedAnnotationClass.class, Order.class).getRootDeclaringClass()).isEqualTo(NonInheritedAnnotationClass.class);
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesForNonInheritedAnnotationOnInterface() {
// Note: @Order is not inherited.
Order rawAnnotation = NonInheritedAnnotationInterface.class.getAnnotation(Order.class);
UntypedAnnotationDescriptor descriptor =
findAnnotationDescriptorForTypes(NonInheritedAnnotationInterface.class, Order.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(NonInheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(NonInheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
descriptor = findAnnotationDescriptorForTypes(SubNonInheritedAnnotationInterface.class, Order.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(SubNonInheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(NonInheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesWithLocalAndMetaComponentAnnotation() {
Class<Component> annotationType = Component.class;
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(
HasLocalAndMetaComponentAnnotation.class, Transactional.class, annotationType, Order.class);
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(HasLocalAndMetaComponentAnnotation.class);
assertThat(descriptor.getAnnotationType()).isEqualTo(annotationType);
assertThat(descriptor.getComposedAnnotation()).isNull();
assertThat(descriptor.getComposedAnnotationType()).isNull();
}
@Test
void findAnnotationDescriptorForTypesWithMetaComponentAnnotation() {
Class<HasMetaComponentAnnotation> startClass = HasMetaComponentAnnotation.class;
assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(startClass, "meta1", Meta1.class);
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesWithMetaAnnotationWithDefaultAttributes() {
Class<?> startClass = MetaConfigWithDefaultAttributesTestCase.class;
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(startClass,
Service.class, ContextConfiguration.class, Order.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(startClass);
assertThat(descriptor.getAnnotationType()).isEqualTo(annotationType);
assertThat(((ContextConfiguration) descriptor.getAnnotation()).value()).isEqualTo(new Class<?>[] {});
assertThat(descriptor.getAnnotationAttributes().getClassArray("classes")).isEqualTo(new Class<?>[] {MetaConfig.DevConfig.class, MetaConfig.ProductionConfig.class});
assertThat(descriptor.getComposedAnnotation()).isNotNull();
assertThat(descriptor.getComposedAnnotationType()).isEqualTo(MetaConfig.class);
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesWithMetaAnnotationWithOverriddenAttributes() {
Class<?> startClass = MetaConfigWithOverriddenAttributesTestCase.class;
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(
startClass, Service.class, ContextConfiguration.class, Order.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(startClass);
assertThat(descriptor.getAnnotationType()).isEqualTo(annotationType);
assertThat(((ContextConfiguration) descriptor.getAnnotation()).value()).isEqualTo(new Class<?>[] {});
assertThat(descriptor.getAnnotationAttributes().getClassArray("classes")).isEqualTo(new Class<?>[] {MetaAnnotationUtilsTests.class});
assertThat(descriptor.getComposedAnnotation()).isNotNull();
assertThat(descriptor.getComposedAnnotationType()).isEqualTo(MetaConfig.class);
}
@Test
void findAnnotationDescriptorForTypesForInterfaceWithMetaAnnotation() {
Class<InterfaceWithMetaAnnotation> startClass = InterfaceWithMetaAnnotation.class;
assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(startClass, "meta1", Meta1.class);
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesForClassWithMetaAnnotatedInterface() {
Component rawAnnotation = AnnotationUtils.findAnnotation(ClassWithMetaAnnotatedInterface.class, Component.class);
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(
ClassWithMetaAnnotatedInterface.class, Service.class, Component.class, Order.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(ClassWithMetaAnnotatedInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(Meta1.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
assertThat(descriptor.getComposedAnnotation().annotationType()).isEqualTo(Meta1.class);
}
@Test
void findAnnotationDescriptorForTypesForClassWithLocalMetaAnnotationAndMetaAnnotatedInterface() {
Class<ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface> startClass = ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class;
assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(startClass, "meta2", Meta2.class);
}
@Test
void findAnnotationDescriptorForTypesForSubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface() {
assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(
SubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class,
ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class, "meta2", Meta2.class);
}
/**
* @since 4.0.3
*/
@Test
void findAnnotationDescriptorForTypesOnMetaMetaAnnotatedClass() {
Class<MetaMetaAnnotatedClass> startClass = MetaMetaAnnotatedClass.class;
assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(
startClass, startClass, Meta2.class, "meta2", MetaMeta.class);
}
/**
* @since 4.0.3
*/
@Test
void findAnnotationDescriptorForTypesOnMetaMetaMetaAnnotatedClass() {
Class<MetaMetaMetaAnnotatedClass> startClass = MetaMetaMetaAnnotatedClass.class;
assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(
startClass, startClass, Meta2.class, "meta2", MetaMetaMeta.class);
}
/**
* @since 4.0.3
*/
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesOnAnnotatedClassWithMissingTargetMetaAnnotation() {
// InheritedAnnotationClass is NOT annotated or meta-annotated with @Component,
// @Service, or @Order, but it is annotated with @Transactional.
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(
InheritedAnnotationClass.class, Service.class, Component.class, Order.class);
assertThat(descriptor).as("Should not find @Component on InheritedAnnotationClass").isNull();
}
/**
* @since 4.0.3
*/
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesOnMetaCycleAnnotatedClassWithMissingTargetMetaAnnotation() {
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(
MetaCycleAnnotatedClass.class, Service.class, Component.class, Order.class);
assertThat(descriptor).as("Should not find @Component on MetaCycleAnnotatedClass").isNull();
}
private void assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(
Class<?> startClass, String name, Class<? extends Annotation> composedAnnotationType) {
assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(
startClass, startClass, name, composedAnnotationType);
}
private void assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(Class<?> startClass,
Class<?> rootDeclaringClass, String name, Class<? extends Annotation> composedAnnotationType) {
assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(
startClass, rootDeclaringClass, composedAnnotationType, name, composedAnnotationType);
}
@SuppressWarnings("unchecked")
private void assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(Class<?> startClass,
Class<?> rootDeclaringClass, Class<?> declaringClass, String name,
Class<? extends Annotation> composedAnnotationType) {
Class<Component> annotationType = Component.class;
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(
startClass, Service.class, annotationType, Order.class, Transactional.class);
assertThat(descriptor).as("UntypedAnnotationDescriptor should not be null").isNotNull();
assertThat(descriptor.getRootDeclaringClass()).as("rootDeclaringClass").isEqualTo(rootDeclaringClass);
assertThat(descriptor.getDeclaringClass()).as("declaringClass").isEqualTo(declaringClass);
assertThat(descriptor.getAnnotationType()).as("annotationType").isEqualTo(annotationType);
assertThat(((Component) descriptor.getAnnotation()).value()).as("component name").isEqualTo(name);
assertThat(descriptor.getComposedAnnotation()).as("composedAnnotation should not be null").isNotNull();
assertThat(descriptor.getComposedAnnotationType()).as("composedAnnotationType").isEqualTo(composedAnnotationType);
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesWithNoAnnotationPresent() {
assertThat(findAnnotationDescriptorForTypes(NonAnnotatedInterface.class, Transactional.class, Component.class)).isNull();
assertThat(findAnnotationDescriptorForTypes(NonAnnotatedClass.class, Transactional.class, Order.class)).isNull();
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesWithInheritedAnnotationOnClass() {
// Note: @Transactional is inherited
assertThat(findAnnotationDescriptorForTypes(InheritedAnnotationClass.class, Transactional.class).getRootDeclaringClass()).isEqualTo(InheritedAnnotationClass.class);
assertThat(findAnnotationDescriptorForTypes(SubInheritedAnnotationClass.class, Transactional.class).getRootDeclaringClass()).isEqualTo(InheritedAnnotationClass.class);
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesWithInheritedAnnotationOnInterface() {
// Note: @Transactional is inherited
Transactional rawAnnotation = InheritedAnnotationInterface.class.getAnnotation(Transactional.class);
UntypedAnnotationDescriptor descriptor =
findAnnotationDescriptorForTypes(InheritedAnnotationInterface.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(InheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(InheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
descriptor = findAnnotationDescriptorForTypes(SubInheritedAnnotationInterface.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(SubInheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(InheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
descriptor = findAnnotationDescriptorForTypes(SubSubInheritedAnnotationInterface.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(SubSubInheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(InheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesForNonInheritedAnnotationOnClass() {
// Note: @Order is not inherited.
assertThat(findAnnotationDescriptorForTypes(NonInheritedAnnotationClass.class, Order.class).getRootDeclaringClass()).isEqualTo(NonInheritedAnnotationClass.class);
assertThat(findAnnotationDescriptorForTypes(SubNonInheritedAnnotationClass.class, Order.class).getRootDeclaringClass()).isEqualTo(NonInheritedAnnotationClass.class);
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesForNonInheritedAnnotationOnInterface() {
// Note: @Order is not inherited.
Order rawAnnotation = NonInheritedAnnotationInterface.class.getAnnotation(Order.class);
UntypedAnnotationDescriptor descriptor =
findAnnotationDescriptorForTypes(NonInheritedAnnotationInterface.class, Order.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(NonInheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(NonInheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
descriptor = findAnnotationDescriptorForTypes(SubNonInheritedAnnotationInterface.class, Order.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(SubNonInheritedAnnotationInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(NonInheritedAnnotationInterface.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesWithLocalAndMetaComponentAnnotation() {
Class<Component> annotationType = Component.class;
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(
HasLocalAndMetaComponentAnnotation.class, Transactional.class, annotationType, Order.class);
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(HasLocalAndMetaComponentAnnotation.class);
assertThat(descriptor.getAnnotationType()).isEqualTo(annotationType);
assertThat(descriptor.getComposedAnnotation()).isNull();
assertThat(descriptor.getComposedAnnotationType()).isNull();
}
@Test
void findAnnotationDescriptorForTypesWithMetaComponentAnnotation() {
Class<HasMetaComponentAnnotation> startClass = HasMetaComponentAnnotation.class;
assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(startClass, "meta1", Meta1.class);
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesWithMetaAnnotationWithDefaultAttributes() {
Class<?> startClass = MetaConfigWithDefaultAttributesTestCase.class;
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(startClass,
Service.class, ContextConfiguration.class, Order.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(startClass);
assertThat(descriptor.getAnnotationType()).isEqualTo(annotationType);
assertThat(((ContextConfiguration) descriptor.getAnnotation()).value()).isEqualTo(new Class<?>[] {});
assertThat(descriptor.getAnnotationAttributes().getClassArray("classes")).isEqualTo(new Class<?>[] {MetaConfig.DevConfig.class, MetaConfig.ProductionConfig.class});
assertThat(descriptor.getComposedAnnotation()).isNotNull();
assertThat(descriptor.getComposedAnnotationType()).isEqualTo(MetaConfig.class);
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesWithMetaAnnotationWithOverriddenAttributes() {
Class<?> startClass = MetaConfigWithOverriddenAttributesTestCase.class;
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(
startClass, Service.class, ContextConfiguration.class, Order.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(startClass);
assertThat(descriptor.getAnnotationType()).isEqualTo(annotationType);
assertThat(((ContextConfiguration) descriptor.getAnnotation()).value()).isEqualTo(new Class<?>[] {});
assertThat(descriptor.getAnnotationAttributes().getClassArray("classes")).isEqualTo(new Class<?>[] {MetaAnnotationUtilsTests.class});
assertThat(descriptor.getComposedAnnotation()).isNotNull();
assertThat(descriptor.getComposedAnnotationType()).isEqualTo(MetaConfig.class);
}
@Test
void findAnnotationDescriptorForTypesForInterfaceWithMetaAnnotation() {
Class<InterfaceWithMetaAnnotation> startClass = InterfaceWithMetaAnnotation.class;
assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(startClass, "meta1", Meta1.class);
}
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesForClassWithMetaAnnotatedInterface() {
Component rawAnnotation = AnnotationUtils.findAnnotation(ClassWithMetaAnnotatedInterface.class, Component.class);
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(
ClassWithMetaAnnotatedInterface.class, Service.class, Component.class, Order.class, Transactional.class);
assertThat(descriptor).isNotNull();
assertThat(descriptor.getRootDeclaringClass()).isEqualTo(ClassWithMetaAnnotatedInterface.class);
assertThat(descriptor.getDeclaringClass()).isEqualTo(Meta1.class);
assertThat(descriptor.getAnnotation()).isEqualTo(rawAnnotation);
assertThat(descriptor.getComposedAnnotation().annotationType()).isEqualTo(Meta1.class);
}
@Test
void findAnnotationDescriptorForTypesForClassWithLocalMetaAnnotationAndMetaAnnotatedInterface() {
Class<ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface> startClass = ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class;
assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(startClass, "meta2", Meta2.class);
}
@Test
void findAnnotationDescriptorForTypesForSubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface() {
assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(
SubClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class,
ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class, "meta2", Meta2.class);
}
/**
* @since 4.0.3
*/
@Test
void findAnnotationDescriptorForTypesOnMetaMetaAnnotatedClass() {
Class<MetaMetaAnnotatedClass> startClass = MetaMetaAnnotatedClass.class;
assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(
startClass, startClass, Meta2.class, "meta2", MetaMeta.class);
}
/**
* @since 4.0.3
*/
@Test
void findAnnotationDescriptorForTypesOnMetaMetaMetaAnnotatedClass() {
Class<MetaMetaMetaAnnotatedClass> startClass = MetaMetaMetaAnnotatedClass.class;
assertAtComponentOnComposedAnnotationForMultipleCandidateTypes(
startClass, startClass, Meta2.class, "meta2", MetaMetaMeta.class);
}
/**
* @since 4.0.3
*/
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesOnAnnotatedClassWithMissingTargetMetaAnnotation() {
// InheritedAnnotationClass is NOT annotated or meta-annotated with @Component,
// @Service, or @Order, but it is annotated with @Transactional.
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(
InheritedAnnotationClass.class, Service.class, Component.class, Order.class);
assertThat(descriptor).as("Should not find @Component on InheritedAnnotationClass").isNull();
}
/**
* @since 4.0.3
*/
@Test
@SuppressWarnings("unchecked")
void findAnnotationDescriptorForTypesOnMetaCycleAnnotatedClassWithMissingTargetMetaAnnotation() {
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(
MetaCycleAnnotatedClass.class, Service.class, Component.class, Order.class);
assertThat(descriptor).as("Should not find @Component on MetaCycleAnnotatedClass").isNull();
}
// -------------------------------------------------------------------------
@Component(value = "meta1")
@Order
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
static @interface Meta1 {
@interface Meta1 {
}
@Component(value = "meta2")
@Transactional
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
static @interface Meta2 {
@interface Meta2 {
}
@Meta2
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@interface MetaMeta {
}
@MetaMeta
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@interface MetaMetaMeta {
}
@MetaCycle3
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
@Documented
@interface MetaCycle1 {
}
@MetaCycle1
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
@Documented
@interface MetaCycle2 {
}
@MetaCycle2
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@interface MetaCycle3 {
}
@ContextConfiguration
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
static @interface MetaConfig {
@interface MetaConfig {
static class DevConfig {
}
@@ -554,7 +555,7 @@ class MetaAnnotationUtilsTests {
}
@Meta1
static interface InterfaceWithMetaAnnotation {
interface InterfaceWithMetaAnnotation {
}
static class ClassWithMetaAnnotatedInterface implements InterfaceWithMetaAnnotation {
@@ -591,26 +592,26 @@ class MetaAnnotationUtilsTests {
// -------------------------------------------------------------------------
@Transactional
static interface InheritedAnnotationInterface {
interface InheritedAnnotationInterface {
}
static interface SubInheritedAnnotationInterface extends InheritedAnnotationInterface {
interface SubInheritedAnnotationInterface extends InheritedAnnotationInterface {
}
static interface SubSubInheritedAnnotationInterface extends SubInheritedAnnotationInterface {
interface SubSubInheritedAnnotationInterface extends SubInheritedAnnotationInterface {
}
@Order
static interface NonInheritedAnnotationInterface {
interface NonInheritedAnnotationInterface {
}
static interface SubNonInheritedAnnotationInterface extends NonInheritedAnnotationInterface {
interface SubNonInheritedAnnotationInterface extends NonInheritedAnnotationInterface {
}
static class NonAnnotatedClass {
}
static interface NonAnnotatedInterface {
interface NonAnnotatedInterface {
}
@Transactional