From ab7b5e5c77f9408e4fab04e8661a93f97acdd6e9 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Wed, 31 Aug 2016 19:35:00 +0200 Subject: [PATCH] Demo how to use SpringClassRule in nested test classes Due to restrictions imposed by JUnit 4, the SpringClassRule must be declared as a public static field, which makes it impossible to be declared directly within a nested (i.e., inner) test class. This commit demonstrates a work-around that makes it possible to use the SpringClassRule and SpringMethodRule in a nested (i.e., inner) test class when using a custom JUnit 4 runner such as the HierarchicalContextRunner from Stefan Bechtold. The trick is to have inner test classes extend a class that properly declares the SpringClassRule and SpringMethodRule. The SpringRuleConfigurer in this commit serves as an example. Note, however, that each such nested test class must declare its own @ContextConfiguration. Furthermore, TestExecutionListeners in the Spring TestContext Framework are not applied to the enclosing instance of such an inner test class, meaning that @Autowired fields in the enclosing instance will not be injected, etc. Issue: SPR-14150 --- build.gradle | 2 + .../NestedTestsWithSpringRulesTests.java | 97 +++++++++++++++++++ .../junit4/nested/SpringRuleConfigurer.java | 40 ++++++++ 3 files changed, 139 insertions(+) create mode 100644 spring-test/src/test/java/org/springframework/test/context/junit4/nested/NestedTestsWithSpringRulesTests.java create mode 100644 spring-test/src/test/java/org/springframework/test/context/junit4/nested/SpringRuleConfigurer.java diff --git a/build.gradle b/build.gradle index f1e342f7ca..952d6c5d38 100644 --- a/build.gradle +++ b/build.gradle @@ -1022,6 +1022,8 @@ project("spring-test") { testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}") testCompile("org.apache.httpcomponents:httpclient:${httpclientVersion}") testCompile("javax.cache:cache-api:1.0.0") + testCompile('de.bechte.junit:junit-hierarchicalcontextrunner:4.12.1') + testRuntime("org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}") testRuntime("org.apache.logging.log4j:log4j-jul:${log4jVersion}") // Java Util Logging for JUnit 5 testRuntime("org.ehcache:ehcache:${ehcache3Version}") diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/nested/NestedTestsWithSpringRulesTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/nested/NestedTestsWithSpringRulesTests.java new file mode 100644 index 0000000000..0cad120452 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit4/nested/NestedTestsWithSpringRulesTests.java @@ -0,0 +1,97 @@ +/* + * Copyright 2002-2016 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 + * + * http://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.junit4.nested; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.nested.NestedTestsWithSpringRulesTests.TopLevelConfig; +import org.springframework.test.context.junit4.rules.SpringClassRule; +import org.springframework.test.context.junit4.rules.SpringMethodRule; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import de.bechte.junit.runners.context.HierarchicalContextRunner; + +/** + * JUnit 4 based integration tests for nested test classes that are + * executed via a custom JUnit 4 {@link HierarchicalContextRunner} and Spring's + * {@link SpringClassRule} and {@link SpringMethodRule} support. + * + * @author Sam Brannen + * @since 5.0 + */ +@RunWith(HierarchicalContextRunner.class) +@ContextConfiguration(classes = TopLevelConfig.class) +public class NestedTestsWithSpringRulesTests extends SpringRuleConfigurer { + + @Autowired + String foo; + + + @Test + public void topLevelTest() { + assertEquals("foo", foo); + } + + + @ContextConfiguration(classes = NestedConfig.class) + public class NestedTestCase extends SpringRuleConfigurer { + + @Autowired + String bar; + + + @Test + public void nestedTest() throws Exception { + // Note: the following would fail since TestExecutionListeners in + // the Spring TestContext Framework are not applied to the enclosing + // instance of an inner test class. + // + // assertEquals("foo", foo); + + assertNull("@Autowired field in enclosing instance should be null.", foo); + assertEquals("bar", bar); + } + } + + // ------------------------------------------------------------------------- + + @Configuration + public static class TopLevelConfig { + + @Bean + String foo() { + return "foo"; + } + } + + @Configuration + public static class NestedConfig { + + @Bean + String bar() { + return "bar"; + } + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/nested/SpringRuleConfigurer.java b/spring-test/src/test/java/org/springframework/test/context/junit4/nested/SpringRuleConfigurer.java new file mode 100644 index 0000000000..8f47e230ca --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/junit4/nested/SpringRuleConfigurer.java @@ -0,0 +1,40 @@ +/* + * Copyright 2002-2016 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 + * + * http://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.junit4.nested; + +import org.junit.ClassRule; +import org.junit.Rule; + +import org.springframework.test.context.junit4.rules.SpringClassRule; +import org.springframework.test.context.junit4.rules.SpringMethodRule; + +/** + * Abstract base test class that preconfigures the {@link SpringClassRule} and + * {@link SpringMethodRule}. + * + * @author Sam Brannen + * @since 5.0 + */ +public abstract class SpringRuleConfigurer { + + @ClassRule + public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule(); + + @Rule + public final SpringMethodRule springMethodRule = new SpringMethodRule(); + +} \ No newline at end of file