Skip to content

Commit e274f29

Browse files
committed
Add "testing your auto-configuration" doc section
Closes gh-10011
1 parent 175f451 commit e274f29

File tree

5 files changed

+241
-0
lines changed

5 files changed

+241
-0
lines changed

spring-boot-project/spring-boot-docs/src/main/asciidoc/index.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Phillip Webb; Dave Syer; Josh Long; Stéphane Nicoll; Rob Winch; Andy Wilkinson;
5353
:propdeps-plugin: https://github.com/spring-projects/gradle-plugins/tree/master/propdeps-plugin
5454
:ant-manual: http://ant.apache.org/manual
5555
:code-examples: ../java/org/springframework/boot
56+
:test-examples: ../../test/java/org/springframework/boot
5657
:gradle-user-guide: https://docs.gradle.org/4.2.1/userguide
5758
:hibernate-documentation: http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html
5859
:jetty-documentation: https://www.eclipse.org/jetty/documentation/9.4.x

spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7101,6 +7101,66 @@ result of a {spring-reference}core.html#expressions[SpEL expression].
71017101

71027102

71037103

7104+
[[boot-features-test-autoconfig]]
7105+
=== Testing your auto-configuration
7106+
An auto-configuration can be affected by many factors: user configuration (`@Bean`
7107+
definition and `Environment` customization), condition evaluation (presence of a
7108+
particular library), etc. Concretely, each test should create a well-defined
7109+
`ApplicationContext` that represents a combination of those customizations and
7110+
`ApplicationContextRunner` provides a great way to achieve that.
7111+
7112+
`ApplicationContextRunner` is usually defined as a field of the test class to gather the
7113+
base, common configuration. The following makes sure that `UserServiceAutoConfiguration`
7114+
is always invoked:
7115+
7116+
[source,java,indent=0]
7117+
----
7118+
include::{test-examples}/autoconfigure/UserServiceAutoConfigurationTests.java[tag=runner]
7119+
----
7120+
7121+
TIP: If multiple auto-configurations have to be defined, there is no need to order their
7122+
declarations as they will be invoked in the exact same order as when running the
7123+
application.
7124+
7125+
Each test can use the runner to represents a particular use case. For instance, the sample
7126+
below invokes a user configuration (`UserConfiguration`) and checks that the
7127+
auto-configuration backs off properly. Invoking `run` provides a callback context that can
7128+
be used with `Assert4J`:
7129+
7130+
[source,java,indent=0]
7131+
----
7132+
include::{test-examples}/autoconfigure/UserServiceAutoConfigurationTests.java[tag=test-user-config]
7133+
----
7134+
7135+
It is also possible to easily customize the `Environment`:
7136+
7137+
[source,java,indent=0]
7138+
----
7139+
include::{test-examples}/autoconfigure/UserServiceAutoConfigurationTests.java[tag=test-env]
7140+
----
7141+
7142+
7143+
7144+
==== Simulating a web context
7145+
If you need to test an auto-configuration that only operates in a Servlet or Reactive web
7146+
application context, use the `WebApplicationContextRunner` or
7147+
`ReactiveWebApplicationContextRunner` respectively.
7148+
7149+
7150+
7151+
==== Overriding the classpath
7152+
It is also possible to test what happens when a particular class and/or package is not
7153+
present at runtime. Spring Boot ships with a `FilteredClassLoader` that can easily be used
7154+
by the runner. In the example below, we assert that if `UserService` is not present, the
7155+
auto-configuration will be properly disabled:
7156+
7157+
[source,java,indent=0]
7158+
----
7159+
include::{test-examples}/autoconfigure/UserServiceAutoConfigurationTests.java[tag=test-classloader]
7160+
----
7161+
7162+
7163+
71047164
[[boot-features-custom-starter]]
71057165
=== Creating Your Own Starter
71067166
A full Spring Boot starter for a library may contain the following components:
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2012-2017 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 org.springframework.boot.autoconfigure;
18+
19+
/**
20+
* Simple service.
21+
*
22+
* @author Stephane Nicoll
23+
*/
24+
class UserService {
25+
26+
private final String name;
27+
28+
UserService(String name) {
29+
this.name = name;
30+
}
31+
32+
public String getName() {
33+
return this.name;
34+
}
35+
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2012-2017 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 org.springframework.boot.autoconfigure;
18+
19+
import org.springframework.boot.autoconfigure.UserServiceAutoConfiguration.UserProperties;
20+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
21+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
22+
import org.springframework.boot.context.properties.ConfigurationProperties;
23+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
24+
import org.springframework.context.annotation.Bean;
25+
import org.springframework.context.annotation.Configuration;
26+
27+
/**
28+
* Sample auto-configuration.
29+
*
30+
* @author Stephane Nicoll
31+
*/
32+
@Configuration
33+
@ConditionalOnClass(UserService.class)
34+
@EnableConfigurationProperties(UserProperties.class)
35+
public class UserServiceAutoConfiguration {
36+
37+
@Bean
38+
@ConditionalOnMissingBean
39+
public UserService userService(UserProperties properties) {
40+
return new UserService(properties.getName());
41+
}
42+
43+
44+
@ConfigurationProperties("user")
45+
static class UserProperties {
46+
47+
private String name = "test";
48+
49+
public String getName() {
50+
return this.name;
51+
}
52+
53+
public void setName(String name) {
54+
this.name = name;
55+
}
56+
57+
}
58+
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright 2012-2017 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 org.springframework.boot.autoconfigure;
18+
19+
import org.junit.Test;
20+
21+
import org.springframework.boot.test.context.FilteredClassLoader;
22+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
23+
import org.springframework.context.annotation.Bean;
24+
import org.springframework.context.annotation.Configuration;
25+
26+
import static org.assertj.core.api.Assertions.assertThat;
27+
28+
/**
29+
* Tests for {@link UserServiceAutoConfiguration}.
30+
*
31+
* @author Stephane Nicoll
32+
*/
33+
public class UserServiceAutoConfigurationTests {
34+
35+
// tag::runner[]
36+
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
37+
.withConfiguration(AutoConfigurations.of(UserServiceAutoConfiguration.class));
38+
// end::runner[]
39+
40+
// tag::test-env[]
41+
@Test
42+
public void serviceNameCanBeConfigured() {
43+
this.contextRunner.withPropertyValues("user.name=test123")
44+
.run((context) -> {
45+
assertThat(context).hasSingleBean(UserService.class);
46+
assertThat(context.getBean(UserService.class).getName())
47+
.isEqualTo("test123");
48+
});
49+
}
50+
// end::test-env[]
51+
52+
// tag::test-classloader[]
53+
@Test
54+
public void serviceIsIgnoredIfLibraryIsNotPresent() {
55+
this.contextRunner.withClassLoader(new FilteredClassLoader(UserService.class))
56+
.run((context) -> {
57+
assertThat(context).doesNotHaveBean("userService");
58+
});
59+
}
60+
// end::test-classloader[]
61+
62+
63+
// tag::test-user-config[]
64+
@Test
65+
public void defaultServiceBacksOff() {
66+
this.contextRunner.withUserConfiguration(UserConfiguration.class)
67+
.run((context) -> {
68+
assertThat(context).hasSingleBean(UserService.class);
69+
assertThat(context.getBean(UserService.class)).isSameAs(
70+
context.getBean(UserConfiguration.class).myUserService());
71+
});
72+
}
73+
74+
@Configuration
75+
static class UserConfiguration {
76+
77+
@Bean
78+
public UserService myUserService() {
79+
return new UserService("mine");
80+
}
81+
82+
}
83+
// end::test-user-config[]
84+
85+
}

0 commit comments

Comments
 (0)