Skip to content
This repository was archived by the owner on Dec 15, 2021. It is now read-only.

Commit 73db0e2

Browse files
committed
Merge pull request #110 from dsyer/SPR-12031
Add sample code for child contexts in test methods
2 parents 4c417a5 + 9ffa38a commit 73db0e2

9 files changed

+501
-0
lines changed

SPR-12031/pom.xml

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<groupId>org.test</groupId>
7+
<artifactId>demo</artifactId>
8+
<version>0.0.1-SNAPSHOT</version>
9+
<packaging>jar</packaging>
10+
11+
<name>eureka-client</name>
12+
<description>Demo project for Spring Boot</description>
13+
14+
<parent>
15+
<groupId>org.springframework.boot</groupId>
16+
<artifactId>spring-boot-starter-parent</artifactId>
17+
<version>1.3.0.BUILD-SNAPSHOT</version>
18+
<relativePath/> <!-- lookup parent from repository -->
19+
</parent>
20+
21+
<properties>
22+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
23+
<java.version>1.8</java.version>
24+
</properties>
25+
26+
<dependencies>
27+
<dependency>
28+
<groupId>org.springframework.boot</groupId>
29+
<artifactId>spring-boot-starter-web</artifactId>
30+
</dependency>
31+
<dependency>
32+
<groupId>org.springframework.boot</groupId>
33+
<artifactId>spring-boot-devtools</artifactId>
34+
</dependency>
35+
<dependency>
36+
<groupId>org.springframework.boot</groupId>
37+
<artifactId>spring-boot-starter-actuator</artifactId>
38+
</dependency>
39+
<dependency>
40+
<groupId>org.springframework.cloud</groupId>
41+
<artifactId>spring-cloud-starter-config</artifactId>
42+
</dependency>
43+
<dependency>
44+
<groupId>org.springframework.cloud</groupId>
45+
<artifactId>spring-cloud-starter-feign</artifactId>
46+
</dependency>
47+
<dependency>
48+
<groupId>org.springframework.cloud</groupId>
49+
<artifactId>spring-cloud-starter-eureka</artifactId>
50+
</dependency>
51+
<dependency>
52+
<groupId>org.springframework.cloud</groupId>
53+
<artifactId>spring-cloud-starter-ribbon</artifactId>
54+
</dependency>
55+
56+
<dependency>
57+
<groupId>org.springframework.boot</groupId>
58+
<artifactId>spring-boot-starter-test</artifactId>
59+
<scope>test</scope>
60+
</dependency>
61+
</dependencies>
62+
63+
<dependencyManagement>
64+
<dependencies>
65+
<dependency>
66+
<groupId>org.springframework.cloud</groupId>
67+
<artifactId>spring-cloud-starter-parent</artifactId>
68+
<version>Brixton.BUILD-SNAPSHOT</version>
69+
<type>pom</type>
70+
<scope>import</scope>
71+
</dependency>
72+
</dependencies>
73+
</dependencyManagement>
74+
75+
<build>
76+
<plugins>
77+
<plugin>
78+
<groupId>org.springframework.boot</groupId>
79+
<artifactId>spring-boot-maven-plugin</artifactId>
80+
</plugin>
81+
</plugins>
82+
</build>
83+
84+
<repositories>
85+
<repository>
86+
<id>spring-snapshots</id>
87+
<name>Spring Snapshots</name>
88+
<url>https://repo.spring.io/snapshot</url>
89+
<snapshots>
90+
<enabled>true</enabled>
91+
</snapshots>
92+
</repository>
93+
<repository>
94+
<id>spring-milestones</id>
95+
<name>Spring Milestones</name>
96+
<url>https://repo.spring.io/milestone</url>
97+
<snapshots>
98+
<enabled>false</enabled>
99+
</snapshots>
100+
</repository>
101+
</repositories>
102+
<pluginRepositories>
103+
<pluginRepository>
104+
<id>spring-snapshots</id>
105+
<name>Spring Snapshots</name>
106+
<url>https://repo.spring.io/snapshot</url>
107+
<snapshots>
108+
<enabled>true</enabled>
109+
</snapshots>
110+
</pluginRepository>
111+
<pluginRepository>
112+
<id>spring-milestones</id>
113+
<name>Spring Milestones</name>
114+
<url>https://repo.spring.io/milestone</url>
115+
<snapshots>
116+
<enabled>false</enabled>
117+
</snapshots>
118+
</pluginRepository>
119+
</pluginRepositories>
120+
121+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
spring.devtools.remote.secret=dlkfjhd
2+
eureka.instance.secure-virtual-host-name=${spring.application.name:unknown}
3+
ribbon.IsSecure=true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# eureka.client.serviceUrl.defaultZone: https://GkW7hXnMKlMS:FV85Yz5pSaUX@eureka-533e6a77-b50a-49a0-a678-426294b0e48d.cfapps.pez.pivotal.io/eureka/
2+
spring.application.name: eureka-client
3+
spring.cloud.config.uri: ${vcap.services.configservice.credentials.uri:http://localhost:8888}
4+
# spring.cloud.config.failFast: true
5+
logging.level.com.netflix.discovery: OFF
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package demo;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import org.junit.ClassRule;
6+
import org.junit.Rule;
7+
import org.junit.Test;
8+
import org.springframework.beans.factory.annotation.Autowired;
9+
import org.springframework.beans.factory.annotation.Value;
10+
import org.springframework.boot.test.IntegrationTest;
11+
import org.springframework.boot.test.SpringApplicationConfiguration;
12+
import org.springframework.context.annotation.Bean;
13+
import org.springframework.context.annotation.Configuration;
14+
import org.springframework.test.context.BootstrapWith;
15+
import org.springframework.test.context.junit4.rules.SpringClassRule;
16+
17+
import demo.ApplicationTests.Application;
18+
19+
@SpringApplicationConfiguration(classes = Application.class)
20+
@BootstrapWith(ChildContextBootstrapper.class)
21+
@IntegrationTest("logging.level.org.springframework.web=DEBUG")
22+
public class ApplicationTests {
23+
24+
@ClassRule
25+
public static final SpringClassRule springClass = new SpringClassRule();
26+
27+
@Rule
28+
public final ChildMethodRule springMethod = new ChildMethodRule();
29+
30+
@Autowired
31+
private String foo;
32+
33+
@Test
34+
public void contextLoads() {
35+
assertEquals("foo", this.foo);
36+
}
37+
38+
@Test
39+
@ChildSpringApplication(Child.class)
40+
public void contextLoadsChild() {
41+
assertEquals("bar", this.foo);
42+
}
43+
44+
@Test
45+
@ChildSpringApplication(ChildWithValue.class)
46+
@ChildTestProperties("foo=spam")
47+
public void contextLoadsChildWithProperties() {
48+
assertEquals("spam", this.foo);
49+
}
50+
51+
@Configuration
52+
public static class Application {
53+
@Bean
54+
public String foo() {
55+
return "foo";
56+
}
57+
}
58+
59+
@Configuration
60+
public static class Child {
61+
@Bean
62+
public String foo() {
63+
return "bar";
64+
}
65+
}
66+
67+
@Configuration
68+
public static class ChildWithValue {
69+
@Value("${foo}")
70+
private String foo;
71+
72+
@Bean
73+
public String foo() {
74+
return this.foo;
75+
}
76+
}
77+
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package demo;
18+
19+
import org.springframework.test.context.ContextLoader;
20+
import org.springframework.test.context.TestContext;
21+
import org.springframework.test.context.support.AbstractTestContextBootstrapper;
22+
import org.springframework.test.context.support.DelegatingSmartContextLoader;
23+
24+
/**
25+
* @author Dave Syer
26+
*
27+
*/
28+
public class ChildContextBootstrapper extends AbstractTestContextBootstrapper {
29+
30+
@Override
31+
protected Class<? extends ContextLoader> getDefaultContextLoaderClass(
32+
Class<?> testClass) {
33+
return DelegatingSmartContextLoader.class;
34+
}
35+
36+
@Override
37+
public TestContext buildTestContext() {
38+
return new ChildTestContext(getBootstrapContext().getTestClass(), buildMergedContextConfiguration(),
39+
getCacheAwareContextLoaderDelegate());
40+
}
41+
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright 2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package demo;
18+
19+
import java.lang.reflect.Method;
20+
21+
import org.apache.commons.logging.Log;
22+
import org.apache.commons.logging.LogFactory;
23+
import org.junit.runners.model.FrameworkMethod;
24+
import org.junit.runners.model.Statement;
25+
import org.springframework.test.context.TestContext;
26+
import org.springframework.test.context.TestContextManager;
27+
import org.springframework.test.context.junit4.rules.SpringClassRule;
28+
import org.springframework.test.context.junit4.rules.SpringMethodRule;
29+
import org.springframework.test.util.ReflectionTestUtils;
30+
import org.springframework.util.ReflectionUtils;
31+
32+
/**
33+
* @author Dave Syer
34+
*
35+
*/
36+
public class ChildMethodRule extends SpringMethodRule {
37+
38+
private static final Log logger = LogFactory.getLog(ChildMethodRule.class);
39+
40+
@Override
41+
public Statement apply(Statement base, FrameworkMethod frameworkMethod, Object testInstance) {
42+
Class<?> testClass = testInstance.getClass();
43+
Method method = ReflectionUtils.findMethod(SpringClassRule.class, "getTestContextManager", Class.class);
44+
ReflectionUtils.makeAccessible(method);
45+
TestContextManager testContextManager = (TestContextManager) ReflectionUtils.invokeMethod(method, null, testClass);
46+
TestContext testContext = (TestContext) ReflectionTestUtils.getField(testContextManager, "testContext");
47+
48+
if (logger.isDebugEnabled()) {
49+
logger.debug("Applying ChildMethodRule to test method [" + frameworkMethod.getMethod() + "].");
50+
}
51+
return new Statement() {
52+
53+
@Override
54+
public void evaluate() throws Throwable {
55+
delegate(base, frameworkMethod, testInstance, testContext);
56+
}
57+
58+
};
59+
}
60+
61+
public void delegate(Statement base, FrameworkMethod frameworkMethod, Object testInstance, TestContext testContext) throws Throwable {
62+
ChildTestContext child = null;
63+
if (testContext instanceof ChildTestContext) {
64+
child = (ChildTestContext) testContext;
65+
}
66+
if (child!=null) {
67+
child.setTestMethod(frameworkMethod.getMethod());
68+
}
69+
super.apply(base, frameworkMethod, testInstance).evaluate();
70+
if (child!=null) {
71+
// Clean up the child context if there is one
72+
child.close();
73+
}
74+
}
75+
76+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2012-2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package demo;
18+
19+
import java.lang.annotation.Documented;
20+
import java.lang.annotation.ElementType;
21+
import java.lang.annotation.Inherited;
22+
import java.lang.annotation.Retention;
23+
import java.lang.annotation.RetentionPolicy;
24+
import java.lang.annotation.Target;
25+
26+
import org.springframework.core.annotation.AliasFor;
27+
import org.springframework.test.context.ContextConfiguration;
28+
29+
@ContextConfiguration
30+
@Documented
31+
@Inherited
32+
@Retention(RetentionPolicy.RUNTIME)
33+
@Target(ElementType.METHOD)
34+
public @interface ChildSpringApplication {
35+
36+
@AliasFor("classes")
37+
Class<?>[] value() default {};
38+
39+
@AliasFor("value")
40+
Class<?>[] classes() default {};
41+
}

0 commit comments

Comments
 (0)