测试 Spring Boot 应用程序
Spring Boot 应用程序是一个 Spring ApplicationContext
,所以除了你通常对普通 Spring 上下文所做的操作外,不需要做任何特殊的事情来测试它。
外部属性、日志记录和 Spring Boot 的其他功能只有在使用 SpringApplication 创建上下文时才会默认安装到上下文中。
|
Spring Boot 提供了 @SpringBootTest
注解,当你需要 Spring Boot 功能时,它可以作为标准 spring-test
@ContextConfiguration
注解的替代方案。
该注解通过 使用 SpringApplication
创建测试中使用的 ApplicationContext
来工作。
除了 @SpringBootTest
之外,还提供了许多其他注解用于 测试应用程序的特定部分。
如果你使用 JUnit 4,别忘了在测试中添加 @RunWith(SpringRunner.class) ,否则注解将被忽略。
如果你使用 JUnit 5,则不需要添加等效的 @ExtendWith(SpringExtension.class) ,因为 @SpringBootTest 和其他 @…Test 注解已经用该注解进行了标注。
|
默认情况下,@SpringBootTest
不会启动服务器。
你可以使用 @SpringBootTest
的 webEnvironment
属性来进一步优化测试的运行方式:
-
MOCK
(默认) : 加载一个 webApplicationContext
并提供模拟的 web 环境。 使用此注解时不会启动嵌入式服务器。 如果你的类路径上没有可用的 web 环境,此模式会透明地回退到创建常规的非 webApplicationContext
。 它可以与@AutoConfigureMockMvc
或@AutoConfigureWebTestClient
结合使用,用于基于模拟的 web 应用程序测试。 -
RANDOM_PORT
: 加载一个WebServerApplicationContext
并提供真实的 web 环境。 嵌入式服务器会启动并监听随机端口。 -
DEFINED_PORT
: 加载一个WebServerApplicationContext
并提供真实的 web 环境。 嵌入式服务器会启动并监听定义的端口(来自你的application.properties
)或默认端口8080
。 -
NONE
: 通过使用SpringApplication
加载ApplicationContext
,但不提供任何 web 环境(模拟或其他)。
如果你的测试是 @Transactional ,默认情况下它会在每个测试方法结束时回滚事务。
但是,由于使用这种安排与 RANDOM_PORT 或 DEFINED_PORT 隐式提供了真实的 servlet 环境,HTTP 客户端和服务器在单独的线程中运行,因此也在单独的事务中。
在这种情况下,服务器上启动的任何事务都不会回滚。
|
如果你的应用程序为管理服务器使用不同的端口,@SpringBootTest 与 webEnvironment = WebEnvironment.RANDOM_PORT 也会在单独的随机端口上启动管理服务器。
|
检测 Web 应用程序类型
如果 Spring MVC 可用,则配置基于 MVC 的常规应用程序上下文。 如果你只有 Spring WebFlux,我们将检测到它并配置基于 WebFlux 的应用程序上下文。
如果两者都存在,Spring MVC 优先。
如果你想在这种情况下测试响应式 web 应用程序,你必须设置 spring.main.web-application-type
属性:
-
Java
-
Kotlin
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest(properties = "spring.main.web-application-type=reactive")
class MyWebFluxTests {
// ...
}
import org.springframework.boot.test.context.SpringBootTest
@SpringBootTest(properties = ["spring.main.web-application-type=reactive"])
class MyWebFluxTests {
// ...
}
检测测试配置
如果你熟悉 Spring Test Framework,你可能习惯于使用 @ContextConfiguration(classes=…)
来指定要加载的 Spring @Configuration
。
或者,你可能经常在测试中使用嵌套的 @Configuration
类。
在测试 Spring Boot 应用程序时,这通常不是必需的。
Spring Boot 的 @*Test
注解会在你没有明确定义配置时自动搜索你的主配置。
搜索算法从包含测试的包开始向上搜索,直到找到带有 @SpringBootApplication
或 @SpringBootConfiguration
注解的类。
只要你以合理的方式 组织你的代码,通常都能找到你的主配置。
如果你使用 测试注解来测试应用程序的特定部分,你应该避免在 主方法的应用程序类上添加特定于某个区域的配置设置。
|
如果你想自定义主配置,你可以使用嵌套的 @TestConfiguration
类。
与嵌套的 @Configuration
类(它会替代你的应用程序的主配置)不同,嵌套的 @TestConfiguration
类会与你的应用程序的主配置一起使用。
Spring 的测试框架会在测试之间缓存应用程序上下文。 因此,只要你的测试共享相同的配置(无论它是如何被发现的),加载上下文的潜在耗时过程只会发生一次。 |
使用测试配置的主方法
通常,@SpringBootTest
发现的测试配置将是你的主 @SpringBootApplication
。
在大多数结构良好的应用程序中,这个配置类还将包含用于启动应用程序的 main
方法。
例如,以下是一个典型的 Spring Boot 应用程序的常见代码模式:
-
Java
-
Kotlin
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.docs.using.structuringyourcode.locatingthemainclass.MyApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}
在上面的例子中,main
方法除了委托给 SpringApplication.run(Class, String…)
之外没有做任何事情。
但是,可以在调用 SpringApplication.run(Class, String…)
之前应用自定义的 main
方法。
例如,这里是一个更改横幅模式和设置其他配置文件的应用程序:
-
Java
-
Kotlin
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.setBannerMode(Banner.Mode.OFF);
application.setAdditionalProfiles("myprofile");
application.run(args);
}
}
import org.springframework.boot.Banner
import org.springframework.boot.runApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args) {
setBannerMode(Banner.Mode.OFF)
setAdditionalProfiles("myprofile")
}
}
由于 main
方法中的自定义可能会影响生成的 ApplicationContext
,你可能还想使用 main
方法来创建测试中使用的 ApplicationContext
。
默认情况下,@SpringBootTest
不会调用你的 main
方法,而是直接使用类本身来创建 ApplicationContext
。
如果你想改变这个行为,你可以将 @SpringBootTest
的 useMainMethod
属性更改为 SpringBootTest.UseMainMethod.ALWAYS
或 SpringBootTest.UseMainMethod.WHEN_AVAILABLE
。
当设置为 ALWAYS
时,如果找不到 main
方法,测试将失败。
当设置为 WHEN_AVAILABLE
时,如果 main
方法可用,将使用它,否则将使用标准加载机制。
例如,以下测试将调用 MyApplication
的 main
方法来创建 ApplicationContext
。
如果 main 方法设置了其他配置文件,那么当 ApplicationContext
启动时,这些配置文件将处于活动状态。
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.UseMainMethod;
@SpringBootTest(useMainMethod = UseMainMethod.ALWAYS)
class MyApplicationTests {
@Test
void exampleTest() {
// ...
}
}
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.UseMainMethod
@SpringBootTest(useMainMethod = UseMainMethod.ALWAYS)
class MyApplicationTests {
@Test
fun exampleTest() {
// ...
}
}
排除测试配置
如果你的应用程序使用组件扫描(例如,如果你使用 @SpringBootApplication
或 @ComponentScan
),你可能会发现仅为特定测试创建的顶级配置类意外地被到处拾取。
正如我们 之前看到的,@TestConfiguration
可以用于测试的内部类来自定义主配置。
@TestConfiguration
也可以用于顶级类。这样做表示该类不应被扫描拾取。
然后你可以在需要的地方显式导入该类,如下例所示:
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
@SpringBootTest
@Import(MyTestsConfiguration.class)
class MyTests {
@Test
void exampleTest() {
// ...
}
}
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.context.annotation.Import
@SpringBootTest
@Import(MyTestsConfiguration::class)
class MyTests {
@Test
fun exampleTest() {
// ...
}
}
如果你直接使用 @ComponentScan (即不是通过 @SpringBootApplication ),你需要向其注册 TypeExcludeFilter 。
有关详细信息,请参阅 TypeExcludeFilter API 文档。
|
导入的 @TestConfiguration 比内部类 @TestConfiguration 更早处理,并且导入的 @TestConfiguration 会在通过组件扫描找到的任何配置之前处理。
一般来说,这种排序差异没有明显的影响,但如果你依赖 bean 覆盖,这是需要注意的。
|
使用应用程序参数
如果你的应用程序需要 参数,你可以
让 @SpringBootTest
使用 args
属性注入它们。
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.test.context.SpringBootTest;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(args = "--app.test=one")
class MyApplicationArgumentTests {
@Test
void applicationArgumentsPopulated(@Autowired ApplicationArguments args) {
assertThat(args.getOptionNames()).containsOnly("app.test");
assertThat(args.getOptionValues("app.test")).containsOnly("one");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.ApplicationArguments
import org.springframework.boot.test.context.SpringBootTest
@SpringBootTest(args = ["--app.test=one"])
class MyApplicationArgumentTests {
@Test
fun applicationArgumentsPopulated(@Autowired args: ApplicationArguments) {
assertThat(args.optionNames).containsOnly("app.test")
assertThat(args.getOptionValues("app.test")).containsOnly("one")
}
}
使用模拟环境进行测试
默认情况下,@SpringBootTest
不会启动服务器,而是设置一个模拟环境来测试 web 端点。
使用 Spring MVC,我们可以使用 MockMvc
查询我们的 web 端点。
提供了三种集成:
-
使用 Hamcrest 的常规
MockMvc
。 -
MockMvcTester
,它包装了MockMvc
并使用 AssertJ。 -
WebTestClient
,其中MockMvc
被插入作为服务器来处理请求。
以下示例展示了可用的集成:
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
class MyMockMvcTests {
@Test
void testWithMockMvc(@Autowired MockMvc mvc) throws Exception {
mvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("Hello World"));
}
// If AssertJ is on the classpath, you can use MockMvcTester
@Test
void testWithMockMvcTester(@Autowired MockMvcTester mvc) {
assertThat(mvc.get().uri("/")).hasStatusOk().hasBodyTextEqualTo("Hello World");
}
// If Spring WebFlux is on the classpath, you can drive MVC tests with a WebTestClient
@Test
void testWithWebTestClient(@Autowired WebTestClient webClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello World");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.test.web.reactive.server.expectBody
import org.springframework.test.web.servlet.assertj.MockMvcTester
@SpringBootTest
@AutoConfigureMockMvc
class MyMockMvcTests {
@Test
fun testWithMockMvc(@Autowired mvc: MockMvcTester) {
assertThat(mvc.get().uri("/")).hasStatusOk()
.hasBodyTextEqualTo("Hello World")
}
// If Spring WebFlux is on the classpath, you can drive MVC tests with a WebTestClient
@Test
fun testWithWebTestClient(@Autowired webClient: WebTestClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk
.expectBody<String>().isEqualTo("Hello World")
}
}
如果你只想关注 web 层而不想启动完整的 ApplicationContext ,可以考虑 使用 @WebMvcTest 代替。
|
对于 Spring WebFlux 端点,你可以使用 WebTestClient
,如下例所示:
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.reactive.server.WebTestClient;
@SpringBootTest
@AutoConfigureWebTestClient
class MyMockWebTestClientTests {
@Test
void exampleTest(@Autowired WebTestClient webClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello World");
}
}
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.test.web.reactive.server.expectBody
@SpringBootTest
@AutoConfigureWebTestClient
class MyMockWebTestClientTests {
@Test
fun exampleTest(@Autowired webClient: WebTestClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk
.expectBody<String>().isEqualTo("Hello World")
}
}
在模拟环境中测试通常比使用完整的 servlet 容器运行更快。 但是,由于模拟发生在 Spring MVC 层,依赖较低级别 servlet 容器行为的代码无法直接用 MockMvc 测试。 例如,Spring Boot 的错误处理基于 servlet 容器提供的"`error page`"支持。 这意味着,虽然你可以测试你的 MVC 层按预期抛出和处理异常,但你无法直接测试是否渲染了特定的 自定义错误页面。 如果你需要测试这些较低级别的关注点,你可以按照下一节所述启动一个完全运行的服务器。 |
使用运行中的服务器进行测试
如果你需要启动一个完全运行的服务器,我们建议你使用随机端口。
如果你使用 @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
,每次测试运行时都会随机选择一个可用端口。
@LocalServerPort
注解可用于 注入实际使用的端口到你的测试中。
为了方便起见,需要对已启动的服务器进行 REST 调用的测试还可以自动装配一个 WebTestClient
,它会解析到运行服务器的相对链接,并带有用于验证响应的专用 API,如下例所示:
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.web.reactive.server.WebTestClient;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyRandomPortWebTestClientTests {
@Test
void exampleTest(@Autowired WebTestClient webClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello World");
}
}
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.test.web.reactive.server.expectBody
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyRandomPortWebTestClientTests {
@Test
fun exampleTest(@Autowired webClient: WebTestClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk
.expectBody<String>().isEqualTo("Hello World")
}
}
WebTestClient 也可以与 模拟环境一起使用,通过用 @AutoConfigureWebTestClient 注解你的测试类来移除对运行服务器的需求。
|
这种设置需要类路径上有 spring-webflux
。
如果你不能或不想添加 webflux,Spring Boot 还提供了 TestRestTemplate
工具:
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyRandomPortTestRestTemplateTests {
@Test
void exampleTest(@Autowired TestRestTemplate restTemplate) {
String body = restTemplate.getForObject("/", String.class);
assertThat(body).isEqualTo("Hello World");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
import org.springframework.boot.test.web.client.TestRestTemplate
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyRandomPortTestRestTemplateTests {
@Test
fun exampleTest(@Autowired restTemplate: TestRestTemplate) {
val body = restTemplate.getForObject("/", String::class.java)
assertThat(body).isEqualTo("Hello World")
}
}
自定义 WebTestClient
要自定义 WebTestClient
bean,可以配置一个 WebTestClientBuilderCustomizer
bean。
任何此类 bean 都会接收用于创建 WebTestClient
的 WebTestClient.Builder
。
使用 JMX
由于测试上下文框架会缓存上下文,默认情况下 JMX 是禁用的,以防止相同组件注册到同一个域。
如果此类测试需要访问 MBeanServer
,可以考虑将其标记为 dirty:
-
Java
-
Kotlin
import javax.management.MBeanServer;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(properties = "spring.jmx.enabled=true")
@DirtiesContext
class MyJmxTests {
@Autowired
private MBeanServer mBeanServer;
@Test
void exampleTest() {
assertThat(this.mBeanServer.getDomains()).contains("java.lang");
// ...
}
}
import javax.management.MBeanServer
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.annotation.DirtiesContext
@SpringBootTest(properties = ["spring.jmx.enabled=true"])
@DirtiesContext
class MyJmxTests(@Autowired val mBeanServer: MBeanServer) {
@Test
fun exampleTest() {
assertThat(mBeanServer.domains).contains("java.lang")
// ...
}
}
使用 Observations
如果你为 切片测试 添加了 @AutoConfigureObservability
注解,它会自动配置一个 ObservationRegistry
。
使用 Metrics
无论你的类路径如何,除了内存实现外,meter registries 在使用 @SpringBootTest
时都不会自动配置。
如果你需要在集成测试中将指标导出到其他后端,可以为其添加 @AutoConfigureObservability
注解。
如果你为 切片测试 添加了 @AutoConfigureObservability
注解,它会自动配置一个内存实现的 MeterRegistry
。
在切片测试中,数据导出不支持 @AutoConfigureObservability
注解。
使用 Tracing
无论你的类路径如何,数据上报相关的 tracing 组件在使用 @SpringBootTest
时都不会自动配置。
如果你需要这些组件作为集成测试的一部分,可以为测试添加 @AutoConfigureObservability
注解。
如果你创建了自己的上报组件(例如自定义的 SpanExporter
或 brave.handler.SpanHandler
),并且你不希望它们在测试中生效,可以使用 @ConditionalOnEnabledTracing
注解来禁用它们。
如果你为 切片测试 添加了 @AutoConfigureObservability
注解,它会自动配置一个 no-op 的 Tracer
。
在切片测试中,数据导出不支持 @AutoConfigureObservability
注解。
Mock 和 Spy Bean
在运行测试时,有时需要在应用上下文中 mock 某些组件。 例如,你可能有一个远程服务的 facade,在开发期间无法访问。 Mock 也可以用于模拟在真实环境中难以触发的故障。
Spring Framework 提供了 @MockitoBean
注解,可以用来为 ApplicationContext
中的 bean 定义 Mockito mock。
此外,@MockitoSpyBean
可用于定义 Mockito spy。
更多关于这些特性的内容请参见 Spring Framework 文档。
自动配置测试
Spring Boot 的自动配置系统对应用程序很有效,但有时对测试来说会有点过度。 通常只加载测试应用程序"切片"所需的部分配置会更有帮助。 例如,你可能只想测试 Spring MVC 控制器的 URL 映射是否正确,不希望在这些测试中涉及数据库调用,或者你想测试 JPA 实体,但在这些测试运行时不关心 web 层。
spring-boot-test-autoconfigure
模块包含许多注解,可用于自动配置这些"切片"。
它们的工作方式类似,提供一个 @…Test
注解来加载 ApplicationContext
,以及一个或多个 @AutoConfigure…
注解用于自定义自动配置设置。
每个切片都将组件扫描限制在合适的组件范围,并只加载非常有限的自动配置类。
如果你需要排除其中某个自动配置,大多数 @…Test 注解都提供了 excludeAutoConfiguration 属性。
或者,你可以使用 @ImportAutoConfiguration#exclude 。
|
不支持在一个测试中通过多个 @…Test 注解包含多个"切片"。
如果你需要多个"切片",请选择一个 @…Test 注解,并手动包含其他"切片"的 @AutoConfigure… 注解。
|
你也可以将 @AutoConfigure… 注解与标准的 @SpringBootTest 注解一起使用。
如果你不关心应用程序"切片",但希望获得部分自动配置的测试 bean,可以使用这种组合。
|
自动配置 JSON 测试
-
Jackson
ObjectMapper
,任何@JsonComponent
bean 以及任何 JacksonModule
-
Gson
-
Jsonb
如果你需要配置自动配置的元素,可以使用 @AutoConfigureJsonTesters
注解。
Spring Boot 提供了基于 AssertJ 的辅助类,可与 JSONAssert 和 JsonPath 库配合使用,检查 JSON 是否符合预期。
JacksonTester
、GsonTester
、JsonbTester
和 BasicJsonTester
类分别可用于 Jackson、Gson、Jsonb 和字符串。
在使用 @JsonTest
时,测试类中的任何辅助字段都可以用 @Autowired
注解。
以下示例展示了 Jackson 的测试类:
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.json.JsonTest;
import org.springframework.boot.test.json.JacksonTester;
import static org.assertj.core.api.Assertions.assertThat;
@JsonTest
class MyJsonTests {
@Autowired
private JacksonTester<VehicleDetails> json;
@Test
void serialize() throws Exception {
VehicleDetails details = new VehicleDetails("Honda", "Civic");
// Assert against a `.json` file in the same package as the test
assertThat(this.json.write(details)).isEqualToJson("expected.json");
// Or use JSON path based assertions
assertThat(this.json.write(details)).hasJsonPathStringValue("@.make");
assertThat(this.json.write(details)).extractingJsonPathStringValue("@.make").isEqualTo("Honda");
}
@Test
void deserialize() throws Exception {
String content = "{\"make\":\"Ford\",\"model\":\"Focus\"}";
assertThat(this.json.parse(content)).isEqualTo(new VehicleDetails("Ford", "Focus"));
assertThat(this.json.parseObject(content).getMake()).isEqualTo("Ford");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.json.JsonTest
import org.springframework.boot.test.json.JacksonTester
@JsonTest
class MyJsonTests(@Autowired val json: JacksonTester<VehicleDetails>) {
@Test
fun serialize() {
val details = VehicleDetails("Honda", "Civic")
// Assert against a `.json` file in the same package as the test
assertThat(json.write(details)).isEqualToJson("expected.json")
// Or use JSON path based assertions
assertThat(json.write(details)).hasJsonPathStringValue("@.make")
assertThat(json.write(details)).extractingJsonPathStringValue("@.make").isEqualTo("Honda")
}
@Test
fun deserialize() {
val content = "{\"make\":\"Ford\",\"model\":\"Focus\"}"
assertThat(json.parse(content)).isEqualTo(VehicleDetails("Ford", "Focus"))
assertThat(json.parseObject(content).make).isEqualTo("Ford")
}
}
JSON 辅助类也可以直接在标准单元测试中使用。
如果你没有使用 @JsonTest ,可以在 @BeforeEach 方法中调用辅助类的 initFields 方法。
|
如果你使用 Spring Boot 的 AssertJ 辅助类对某个 JSON 路径的数值进行断言,可能无法直接使用 isEqualTo
,具体取决于类型。
你可以使用 AssertJ 的 satisfies
来断言该值符合给定条件。
例如,下面的例子断言实际数值是接近 0.15
的浮点数,允许偏差为 0.01
。
-
Java
-
Kotlin
@Test
void someTest() throws Exception {
SomeObject value = new SomeObject(0.152f);
assertThat(this.json.write(value)).extractingJsonPathNumberValue("@.test.numberValue")
.satisfies((number) -> assertThat(number.floatValue()).isCloseTo(0.15f, within(0.01f)));
}
@Test
fun someTest() {
val value = SomeObject(0.152f)
assertThat(json.write(value)).extractingJsonPathNumberValue("@.test.numberValue")
.satisfies(ThrowingConsumer { number ->
assertThat(number.toFloat()).isCloseTo(0.15f, within(0.01f))
})
}
自动配置 Spring MVC 测试
要测试 Spring MVC 控制器是否按预期工作,请使用 @WebMvcTest
注解。
@WebMvcTest
会自动配置 Spring MVC 基础设施,并将扫描的 bean 限制为 @Controller
、@ControllerAdvice
、@JsonComponent
、Converter
、GenericConverter
、Filter
、HandlerInterceptor
、WebMvcConfigurer
、WebMvcRegistrations
和 HandlerMethodArgumentResolver
。
当使用 @WebMvcTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
bean。
@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
bean。
@WebMvcTest 启用的自动配置设置列表可在 附录中找到。
|
通常,@WebMvcTest
只针对单个控制器,并与 @MockitoBean
结合使用,为所需的协作者提供 mock 实现。
@WebMvcTest
还会自动配置 MockMvc
。
Mock MVC 提供了一种强大的方式,可以快速测试 MVC 控制器,而无需启动完整的 HTTP 服务器。
如果可用,还会自动配置 MockMvcTester
提供的 AssertJ 支持。
你也可以在非 @WebMvcTest (如 @SpringBootTest )中,通过添加 @AutoConfigureMockMvc 注解,自动配置 MockMvc 和 MockMvcTester 。
以下示例使用了 MockMvcTester :
|
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
@WebMvcTest(UserVehicleController.class)
class MyControllerTests {
@Autowired
private MockMvcTester mvc;
@MockitoBean
private UserVehicleService userVehicleService;
@Test
void testExample() {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda", "Civic"));
assertThat(this.mvc.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
.hasStatusOk()
.hasBodyTextEqualTo("Honda Civic");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.mockito.BDDMockito.given
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.http.MediaType
import org.springframework.test.context.bean.override.mockito.MockitoBean
import org.springframework.test.web.servlet.assertj.MockMvcTester
@WebMvcTest(UserVehicleController::class)
class MyControllerTests(@Autowired val mvc: MockMvcTester) {
@MockitoBean
lateinit var userVehicleService: UserVehicleService
@Test
fun testExample() {
given(userVehicleService.getVehicleDetails("sboot"))
.willReturn(VehicleDetails("Honda", "Civic"))
assertThat(mvc.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
.hasStatusOk().hasBodyTextEqualTo("Honda Civic")
}
}
如果你需要配置自动配置的元素(例如,何时应用 servlet 过滤器),可以在 @AutoConfigureMockMvc 注解中使用属性。
|
如果你使用 HtmlUnit 和 Selenium,自动配置还会提供 HtmlUnit 的 WebClient
bean 和/或 Selenium 的 WebDriver
bean。
以下示例使用了 HtmlUnit:
-
Java
-
Kotlin
import org.htmlunit.WebClient;
import org.htmlunit.html.HtmlPage;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
@WebMvcTest(UserVehicleController.class)
class MyHtmlUnitTests {
@Autowired
private WebClient webClient;
@MockitoBean
private UserVehicleService userVehicleService;
@Test
void testExample() throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot")).willReturn(new VehicleDetails("Honda", "Civic"));
HtmlPage page = this.webClient.getPage("/sboot/vehicle.html");
assertThat(page.getBody().getTextContent()).isEqualTo("Honda Civic");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.htmlunit.WebClient
import org.htmlunit.html.HtmlPage
import org.junit.jupiter.api.Test
import org.mockito.BDDMockito.given
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.test.context.bean.override.mockito.MockitoBean
@WebMvcTest(UserVehicleController::class)
class MyHtmlUnitTests(@Autowired val webClient: WebClient) {
@MockitoBean
lateinit var userVehicleService: UserVehicleService
@Test
fun testExample() {
given(userVehicleService.getVehicleDetails("sboot")).willReturn(VehicleDetails("Honda", "Civic"))
val page = webClient.getPage<HtmlPage>("/sboot/vehicle.html")
assertThat(page.body.textContent).isEqualTo("Honda Civic")
}
}
默认情况下,Spring Boot 会将 WebDriver bean 放在一个特殊的"`scope`"中,以确保每个测试后驱动程序退出并注入新实例。
如果你不想要这种行为,可以在 WebDriver 的 @Bean 定义上添加 @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) 。
|
Spring Boot 创建的 webDriver scope 会替换任何用户自定义的同名 scope。
如果你自定义了 webDriver scope,使用 @WebMvcTest 时可能会发现它不再生效。
|
如果类路径上有 Spring Security,@WebMvcTest
还会扫描 WebSecurityConfigurer
bean。
对于此类测试,不必完全禁用安全性,可以使用 Spring Security 的测试支持。
关于如何使用 Spring Security 的 MockMvc
支持的更多细节,请参见 使用 Spring Security 进行测试"`How-to Guides"`部分。
有时仅编写 Spring MVC 测试还不够;Spring Boot 可以帮助你运行 带有实际服务器的完整端到端测试。 |
自动配置 Spring WebFlux 测试
要测试 Spring WebFlux 控制器是否按预期工作,可以使用 @WebFluxTest
注解。
@WebFluxTest
会自动配置 Spring WebFlux 基础设施,并将扫描的 bean 限制为 @Controller
、@ControllerAdvice
、@JsonComponent
、Converter
、GenericConverter
和 WebFluxConfigurer
。
当使用 @WebFluxTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
bean。
@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
bean。
@WebFluxTest 启用的自动配置列表可在 附录中找到。
|
通常,@WebFluxTest
只针对单个控制器,并与 @MockitoBean
注解结合使用,为所需的协作者提供 mock 实现。
@WebFluxTest
还会自动配置 WebTestClient
,它为 WebFlux 控制器提供了一种强大的快速测试方式,无需启动完整的 HTTP 服务器。
你也可以在非 @WebFluxTest (如 @SpringBootTest )中,通过添加 @AutoConfigureWebTestClient 注解,自动配置 WebTestClient 。
以下示例展示了同时使用 @WebFluxTest 和 WebTestClient 的类:
|
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.mockito.BDDMockito.given;
@WebFluxTest(UserVehicleController.class)
class MyControllerTests {
@Autowired
private WebTestClient webClient;
@MockitoBean
private UserVehicleService userVehicleService;
@Test
void testExample() {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda", "Civic"));
this.webClient.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN).exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Honda Civic");
}
}
import org.junit.jupiter.api.Test
import org.mockito.BDDMockito.given
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest
import org.springframework.http.MediaType
import org.springframework.test.context.bean.override.mockito.MockitoBean
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.test.web.reactive.server.expectBody
@WebFluxTest(UserVehicleController::class)
class MyControllerTests(@Autowired val webClient: WebTestClient) {
@MockitoBean
lateinit var userVehicleService: UserVehicleService
@Test
fun testExample() {
given(userVehicleService.getVehicleDetails("sboot"))
.willReturn(VehicleDetails("Honda", "Civic"))
webClient.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN).exchange()
.expectStatus().isOk
.expectBody<String>().isEqualTo("Honda Civic")
}
}
这种设置目前仅支持 WebFlux 应用,因为在模拟 web 应用中使用 WebTestClient 目前只适用于 WebFlux。
|
@WebFluxTest 无法检测通过函数式 web 框架注册的路由。
要在上下文中测试 RouterFunction bean,可以通过 @Import 或 @SpringBootTest 自行导入。
|
@WebFluxTest 无法检测作为 @Bean 类型 SecurityWebFilterChain 注册的自定义安全配置。
要在测试中包含该配置,需要通过 @Import 或 @SpringBootTest 导入注册该 bean 的配置。
|
有时仅编写 Spring WebFlux 测试还不够;Spring Boot 可以帮助你运行 带有实际服务器的完整端到端测试。 |
自动配置 Spring GraphQL 测试
Spring GraphQL 提供了专门的测试支持模块;你需要将其添加到你的项目中:
<dependencies>
<dependency>
<groupId>org.springframework.graphql</groupId>
<artifactId>spring-graphql-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 如果已在 compile scope 中存在则无需再添加 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
dependencies {
testImplementation("org.springframework.graphql:spring-graphql-test")
// 如果已在 implementation 配置中存在则无需再添加
testImplementation("org.springframework.boot:spring-boot-starter-webflux")
}
该测试模块提供了 GraphQlTester。
该测试器在测试中被大量使用,请务必熟悉其用法。
有多种 GraphQlTester
变体,Spring Boot 会根据测试类型自动配置它们:
-
ExecutionGraphQlServiceTester
在服务端执行测试,无需客户端和传输层 -
HttpGraphQlTester
使用客户端连接到服务器进行测试,可以有或没有真实服务器
Spring Boot 通过 @GraphQlTest
注解帮助你测试 Spring GraphQL Controllers。
@GraphQlTest
会自动配置 Spring GraphQL 基础设施,不涉及任何传输层或服务器。
它将扫描的 bean 限制为 @Controller
、RuntimeWiringConfigurer
、JsonComponent
、Converter
、GenericConverter
、DataFetcherExceptionResolver
、Instrumentation
和 GraphQlSourceBuilderCustomizer
。
当使用 @GraphQlTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
bean。
@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
bean。
@GraphQlTest 启用的自动配置列表可在 附录中找到。
|
通常,@GraphQlTest
只针对一组控制器,并与 @MockitoBean
注解结合使用,为所需的协作者提供 mock 实现。
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.docs.web.graphql.runtimewiring.GreetingController;
import org.springframework.boot.test.autoconfigure.graphql.GraphQlTest;
import org.springframework.graphql.test.tester.GraphQlTester;
@GraphQlTest(GreetingController.class)
class GreetingControllerTests {
@Autowired
private GraphQlTester graphQlTester;
@Test
void shouldGreetWithSpecificName() {
this.graphQlTester.document("{ greeting(name: \"Alice\") } ")
.execute()
.path("greeting")
.entity(String.class)
.isEqualTo("Hello, Alice!");
}
@Test
void shouldGreetWithDefaultName() {
this.graphQlTester.document("{ greeting } ")
.execute()
.path("greeting")
.entity(String.class)
.isEqualTo("Hello, Spring!");
}
}
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.docs.web.graphql.runtimewiring.GreetingController
import org.springframework.boot.test.autoconfigure.graphql.GraphQlTest
import org.springframework.graphql.test.tester.GraphQlTester
@GraphQlTest(GreetingController::class)
internal class GreetingControllerTests {
@Autowired
lateinit var graphQlTester: GraphQlTester
@Test
fun shouldGreetWithSpecificName() {
graphQlTester.document("{ greeting(name: \"Alice\") } ").execute().path("greeting").entity(String::class.java)
.isEqualTo("Hello, Alice!")
}
@Test
fun shouldGreetWithDefaultName() {
graphQlTester.document("{ greeting } ").execute().path("greeting").entity(String::class.java)
.isEqualTo("Hello, Spring!")
}
}
@SpringBootTest
测试是完整的集成测试,涉及整个应用程序。
当使用随机端口或指定端口时,会配置一个真实服务器,并自动提供 HttpGraphQlTester
bean,你可以用它来测试服务器。
当配置为 MOCK 环境时,也可以通过为测试类添加 @AutoConfigureHttpGraphQlTester
注解来请求 HttpGraphQlTester
bean:
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.graphql.tester.AutoConfigureHttpGraphQlTester;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.graphql.test.tester.HttpGraphQlTester;
@AutoConfigureHttpGraphQlTester
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
class GraphQlIntegrationTests {
@Test
void shouldGreetWithSpecificName(@Autowired HttpGraphQlTester graphQlTester) {
HttpGraphQlTester authenticatedTester = graphQlTester.mutate()
.webTestClient((client) -> client.defaultHeaders((headers) -> headers.setBasicAuth("admin", "ilovespring")))
.build();
authenticatedTester.document("{ greeting(name: \"Alice\") } ")
.execute()
.path("greeting")
.entity(String.class)
.isEqualTo("Hello, Alice!");
}
}
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.graphql.tester.AutoConfigureHttpGraphQlTester
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.graphql.test.tester.HttpGraphQlTester
import org.springframework.http.HttpHeaders
import org.springframework.test.web.reactive.server.WebTestClient
@AutoConfigureHttpGraphQlTester
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
class GraphQlIntegrationTests {
@Test
fun shouldGreetWithSpecificName(@Autowired graphQlTester: HttpGraphQlTester) {
val authenticatedTester = graphQlTester.mutate()
.webTestClient { client: WebTestClient.Builder ->
client.defaultHeaders { headers: HttpHeaders ->
headers.setBasicAuth("admin", "ilovespring")
}
}.build()
authenticatedTester.document("{ greeting(name: \"Alice\") } ").execute()
.path("greeting").entity(String::class.java).isEqualTo("Hello, Alice!")
}
}
自动配置 Data Cassandra 测试
你可以使用 @DataCassandraTest
测试 Cassandra 应用。
默认情况下,它会配置 CassandraTemplate
,扫描 @Table
类,并配置 Spring Data Cassandra 仓库。
当使用 @DataCassandraTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
bean。
@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
bean。
(关于在 Spring Boot 中使用 Cassandra 的更多内容,见 Cassandra。)
@DataCassandraTest 启用的自动配置设置列表可在 附录中找到。
|
以下示例展示了在 Spring Boot 中使用 Cassandra 测试的典型设置:
-
Java
-
Kotlin
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.cassandra.DataCassandraTest;
@DataCassandraTest
class MyDataCassandraTests {
@Autowired
private SomeRepository repository;
}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.cassandra.DataCassandraTest
@DataCassandraTest
class MyDataCassandraTests(@Autowired val repository: SomeRepository)
自动配置 Data Couchbase 测试
你可以使用 @DataCouchbaseTest
测试 Couchbase 应用。
默认情况下,它会配置 CouchbaseTemplate
或 ReactiveCouchbaseTemplate
,扫描 @Document
类,并配置 Spring Data Couchbase 仓库。
当使用 @DataCouchbaseTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
bean。
@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
bean。
(关于在 Spring Boot 中使用 Couchbase 的更多内容,见 Couchbase,本章前面。)
@DataCouchbaseTest 启用的自动配置设置列表可在 附录中找到。
|
以下示例展示了在 Spring Boot 中使用 Couchbase 测试的典型设置:
-
Java
-
Kotlin
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.couchbase.DataCouchbaseTest;
@DataCouchbaseTest
class MyDataCouchbaseTests {
@Autowired
private SomeRepository repository;
// ...
}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.couchbase.DataCouchbaseTest
@DataCouchbaseTest
class MyDataCouchbaseTests(@Autowired val repository: SomeRepository) {
// ...
}
自动配置 Data Elasticsearch 测试
你可以使用 @DataElasticsearchTest
测试 Elasticsearch 应用。
默认情况下,它会配置 ElasticsearchTemplate
,扫描 @Document
类,并配置 Spring Data Elasticsearch 仓库。
当使用 @DataElasticsearchTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
bean。
@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
bean。
(关于在 Spring Boot 中使用 Elasticsearch 的更多内容,见 Elasticsearch,本章前面。)
@DataElasticsearchTest 启用的自动配置设置列表可在 附录中找到。
|
以下示例展示了在 Spring Boot 中使用 Elasticsearch 测试的典型设置:
-
Java
-
Kotlin
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.elasticsearch.DataElasticsearchTest;
@DataElasticsearchTest
class MyDataElasticsearchTests {
@Autowired
private SomeRepository repository;
// ...
}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.elasticsearch.DataElasticsearchTest
@DataElasticsearchTest
class MyDataElasticsearchTests(@Autowired val repository: SomeRepository) {
// ...
}
自动配置 Data JPA 测试
你可以使用 @DataJpaTest
注解测试 JPA 应用。
默认情况下,它会扫描 @Entity
类并配置 Spring Data JPA 仓库。
如果类路径上有嵌入式数据库,也会自动配置。
SQL 查询默认通过将 spring.jpa.show-sql
属性设置为 true
进行日志记录。
可以通过注解的 showSql
属性禁用。
当使用 @DataJpaTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
bean。
@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
bean。
@DataJpaTest 启用的自动配置设置列表可在 附录中找到。
|
默认情况下,data JPA 测试是事务性的,并在每个测试结束时回滚。 更多细节请参见 Spring Framework 参考文档相关章节。 如果你不希望这样,可以为某个测试或整个类禁用事务管理,如下所示:
-
Java
-
Kotlin
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyNonTransactionalTests {
// ...
}
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional
@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyNonTransactionalTests {
// ...
}
data JPA 测试还可以注入 TestEntityManager
bean,它是专为测试设计的标准 JPA EntityManager
的替代方案。
你也可以通过添加 @AutoConfigureTestEntityManager ,将 TestEntityManager 自动配置到任何 Spring 测试类中。
这样做时,请确保你的测试运行在事务中,例如在测试类或方法上添加 @Transactional 。
|
如果需要,还可以使用 JdbcTemplate
。
以下示例展示了 @DataJpaTest
注解的用法:
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import static org.assertj.core.api.Assertions.assertThat;
@DataJpaTest
class MyRepositoryTests {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository repository;
@Test
void testExample() {
this.entityManager.persist(new User("sboot", "1234"));
User user = this.repository.findByUsername("sboot");
assertThat(user.getUsername()).isEqualTo("sboot");
assertThat(user.getEmployeeNumber()).isEqualTo("1234");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager
@DataJpaTest
class MyRepositoryTests(@Autowired val entityManager: TestEntityManager, @Autowired val repository: UserRepository) {
@Test
fun testExample() {
entityManager.persist(User("sboot", "1234"))
val user = repository.findByUsername("sboot")
assertThat(user?.username).isEqualTo("sboot")
assertThat(user?.employeeNumber).isEqualTo("1234")
}
}
内存嵌入式数据库通常非常适合测试,因为它们速度快且无需安装。
但如果你更喜欢针对真实数据库运行测试,可以使用 @AutoConfigureTestDatabase
注解,如下例所示:
-
Java
-
Kotlin
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
class MyRepositoryTests {
// ...
}
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class MyRepositoryTests {
// ...
}
自动配置 JDBC 测试
@JdbcTest
类似于 @DataJpaTest
,但仅用于只需要 DataSource
且不使用 Spring Data JDBC 的测试。
默认情况下,它会配置一个内存嵌入式数据库和一个 JdbcTemplate
。
当使用 @JdbcTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
bean。
@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
bean。
默认情况下,JDBC 测试是事务性的,并在每个测试结束时回滚。 更多细节请参见 Spring Framework 参考文档相关章节。 如果你不希望这样,可以为某个测试或整个类禁用事务管理,如下所示:
-
Java
-
Kotlin
import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@JdbcTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyTransactionalTests {
}
import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional
@JdbcTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyTransactionalTests
如果你更喜欢针对真实数据库运行测试,可以像 @DataJpaTest
一样使用 @AutoConfigureTestDatabase
注解。
(见 自动配置 Data JPA 测试。)
自动配置 Data JDBC 测试
@DataJdbcTest
类似于 @JdbcTest
,但用于使用 Spring Data JDBC 仓库的测试。
默认情况下,它会配置一个内存嵌入式数据库、一个 JdbcTemplate
,以及 Spring Data JDBC 仓库。
当使用 @DataJdbcTest
注解时,只会扫描 AbstractJdbcConfiguration
的子类,不会扫描常规的 @Component
和 @ConfigurationProperties
bean。
@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
bean。
@DataJdbcTest 启用的自动配置列表可在 附录中找到。
|
默认情况下,Data JDBC 测试是事务性的,并在每个测试结束时回滚。 更多细节请参见 Spring Framework 参考文档相关章节。 如果你不希望这样,可以为某个测试或整个测试类禁用事务管理,具体见 JDBC 示例。
如果你更喜欢针对真实数据库运行测试,可以像 @DataJpaTest
一样使用 @AutoConfigureTestDatabase
注解。
(见 自动配置 Data JPA 测试。)
自动配置 Data R2DBC 测试
@DataR2dbcTest
类似于 @DataJdbcTest
,但用于使用 Spring Data R2DBC 仓库的测试。
默认情况下,它会配置一个内存嵌入式数据库、一个 R2dbcEntityTemplate
,以及 Spring Data R2DBC 仓库。
当使用 @DataR2dbcTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
bean。
@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
bean。
@DataR2dbcTest 启用的自动配置列表可在 附录中找到。
|
默认情况下,Data R2DBC 测试不是事务性的。
如果你更喜欢针对真实数据库运行测试,可以像 @DataJpaTest
一样使用 @AutoConfigureTestDatabase
注解。
(见 自动配置 Data JPA 测试。)
自动配置 jOOQ 测试
你可以像使用 @JdbcTest
一样使用 @JooqTest
进行 jOOQ 相关测试。
由于 jOOQ 严重依赖与数据库模式对应的 Java 模式,因此会使用现有的 DataSource
。
如果你想用内存数据库替换它,可以使用 @AutoConfigureTestDatabase
覆盖这些设置。
(关于在 Spring Boot 中使用 jOOQ 的更多内容,见 Using jOOQ。)
当使用 @JooqTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
bean。
@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
bean。
@JooqTest
会配置一个 DSLContext
。
以下示例展示了 @JooqTest
注解的用法:
-
Java
-
Kotlin
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jooq.JooqTest;
@JooqTest
class MyJooqTests {
@Autowired
private DSLContext dslContext;
// ...
}
import org.jooq.DSLContext
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.jooq.JooqTest
@JooqTest
class MyJooqTests(@Autowired val dslContext: DSLContext) {
// ...
}
JOOQ 测试默认是事务性的,并在每个测试结束时回滚。 如果你不希望这样,可以为某个测试或整个测试类禁用事务管理,具体见 JDBC 示例。
自动配置 Data MongoDB 测试
你可以使用 @DataMongoTest
测试 MongoDB 应用。
默认情况下,它会配置 MongoTemplate
,扫描 @Document
类,并配置 Spring Data MongoDB 仓库。
当使用 @DataMongoTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
bean。
@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
bean。
(关于在 Spring Boot 中使用 MongoDB 的更多内容,见 MongoDB。)
@DataMongoTest 启用的自动配置设置列表可在 附录中找到。
|
以下示例展示了 @DataMongoTest
注解的用法:
-
Java
-
Kotlin
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.data.mongodb.core.MongoTemplate;
@DataMongoTest
class MyDataMongoDbTests {
@Autowired
private MongoTemplate mongoTemplate;
// ...
}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest
import org.springframework.data.mongodb.core.MongoTemplate
@DataMongoTest
class MyDataMongoDbTests(@Autowired val mongoTemplate: MongoTemplate) {
// ...
}
自动配置 Data Neo4j 测试
你可以使用 @DataNeo4jTest
测试 Neo4j 应用。
默认情况下,它会扫描 @Node
类,并配置 Spring Data Neo4j 仓库。
当使用 @DataNeo4jTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
bean。
@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
bean。
(关于在 Spring Boot 中使用 Neo4J 的更多内容,见 Neo4j。)
@DataNeo4jTest 启用的自动配置设置列表可在 附录中找到。
|
以下示例展示了在 Spring Boot 中使用 Neo4J 测试的典型设置:
-
Java
-
Kotlin
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;
@DataNeo4jTest
class MyDataNeo4jTests {
@Autowired
private SomeRepository repository;
// ...
}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest
@DataNeo4jTest
class MyDataNeo4jTests(@Autowired val repository: SomeRepository) {
// ...
}
By default, Data Neo4j 测试是事务性的,并在每个测试结束时回滚。 更多细节请参见 Spring Framework 参考文档相关章节。 如果你不希望这样,可以为某个测试或整个类禁用事务管理,如下所示:
-
Java
-
Kotlin
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@DataNeo4jTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyDataNeo4jTests {
}
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional
@DataNeo4jTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyDataNeo4jTests
Transactional tests are not supported with reactive access.
If you are using this style, you must configure @DataNeo4jTest tests as described above.
|
自动配置 Data Redis 测试
你可以使用 @DataRedisTest
测试 Redis 应用。
默认情况下,它会扫描 @RedisHash
类并配置 Spring Data Redis 仓库。
当使用 @DataRedisTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
bean。
@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
bean。
(关于在 Spring Boot 中使用 Redis 的更多内容,见 Redis。)
@DataRedisTest 启用的自动配置设置列表可在 附录中找到。
|
以下示例展示了 @DataRedisTest
注解的用法:
-
Java
-
Kotlin
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest;
@DataRedisTest
class MyDataRedisTests {
@Autowired
private SomeRepository repository;
// ...
}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest
@DataRedisTest
class MyDataRedisTests(@Autowired val repository: SomeRepository) {
// ...
}
自动配置 Data LDAP 测试
你可以使用 @DataLdapTest
测试 LDAP 应用。
默认情况下,它会配置一个内存嵌入式 LDAP(如果可用),配置一个 LdapTemplate
,扫描 @Entry
类,并配置 Spring Data LDAP 仓库。
当使用 @DataLdapTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
bean。
@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
bean。
(关于在 Spring Boot 中使用 LDAP 的更多内容,见 LDAP。)
@DataLdapTest 启用的自动配置设置列表可在 附录中找到。
|
以下示例展示了 @DataLdapTest
注解的用法:
-
Java
-
Kotlin
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest;
import org.springframework.ldap.core.LdapTemplate;
@DataLdapTest
class MyDataLdapTests {
@Autowired
private LdapTemplate ldapTemplate;
// ...
}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest
import org.springframework.ldap.core.LdapTemplate
@DataLdapTest
class MyDataLdapTests(@Autowired val ldapTemplate: LdapTemplate) {
// ...
}
内存嵌入式 LDAP 通常非常适合测试,因为它速度快且不需要任何开发者安装。 但如果你更喜欢针对真实 LDAP 服务器运行测试,你应该排除嵌入式 LDAP 自动配置,如下例所示:
-
Java
-
Kotlin
import org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration;
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest;
@DataLdapTest(excludeAutoConfiguration = EmbeddedLdapAutoConfiguration.class)
class MyDataLdapTests {
// ...
}
import org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest
@DataLdapTest(excludeAutoConfiguration = [EmbeddedLdapAutoConfiguration::class])
class MyDataLdapTests {
// ...
}
自动配置 REST 客户端
你可以使用 @RestClientTest
注解测试 REST 客户端。
默认情况下,它会自动配置 Jackson、GSON 和 Jsonb 支持,配置一个 RestTemplateBuilder
和一个 RestClient.Builder
,并添加对 MockRestServiceServer
的支持。
当使用 @RestClientTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
bean。
@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
bean。
@RestClientTest 启用的自动配置设置列表可在 附录中找到。
|
你需要测试的特定 bean 应该通过使用 @RestClientTest
的 value
或 components
属性来指定。
当在测试中使用的 bean 上使用 RestTemplateBuilder
并且 RestTemplateBuilder.rootUri(String rootUri)
在构建 RestTemplate
时被调用时,根 URI 应该从 MockRestServiceServer
期望中省略,如下例所示:
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.client.MockRestServiceServer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
@RestClientTest(org.springframework.boot.docs.testing.springbootapplications.autoconfiguredrestclient.RemoteVehicleDetailsService.class)
class MyRestTemplateServiceTests {
@Autowired
private RemoteVehicleDetailsService service;
@Autowired
private MockRestServiceServer server;
@Test
void getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() {
this.server.expect(requestTo("/greet/details")).andRespond(withSuccess("hello", MediaType.TEXT_PLAIN));
String greeting = this.service.callRestService();
assertThat(greeting).isEqualTo("hello");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest
import org.springframework.http.MediaType
import org.springframework.test.web.client.MockRestServiceServer
import org.springframework.test.web.client.match.MockRestRequestMatchers
import org.springframework.test.web.client.response.MockRestResponseCreators
@RestClientTest(RemoteVehicleDetailsService::class)
class MyRestTemplateServiceTests(
@Autowired val service: RemoteVehicleDetailsService,
@Autowired val server: MockRestServiceServer) {
@Test
fun getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() {
server.expect(MockRestRequestMatchers.requestTo("/greet/details"))
.andRespond(MockRestResponseCreators.withSuccess("hello", MediaType.TEXT_PLAIN))
val greeting = service.callRestService()
assertThat(greeting).isEqualTo("hello")
}
}
当在测试中使用的 bean 上使用 RestClient.Builder
或在 RestTemplateBuilder
上不调用 rootUri(String rootURI)
时,必须使用完整的 URI 在 MockRestServiceServer
期望中,如下例所示:
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.client.MockRestServiceServer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
@RestClientTest(RemoteVehicleDetailsService.class)
class MyRestClientServiceTests {
@Autowired
private RemoteVehicleDetailsService service;
@Autowired
private MockRestServiceServer server;
@Test
void getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() {
this.server.expect(requestTo("https://example.com/greet/details"))
.andRespond(withSuccess("hello", MediaType.TEXT_PLAIN));
String greeting = this.service.callRestService();
assertThat(greeting).isEqualTo("hello");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest
import org.springframework.http.MediaType
import org.springframework.test.web.client.MockRestServiceServer
import org.springframework.test.web.client.match.MockRestRequestMatchers
import org.springframework.test.web.client.response.MockRestResponseCreators
@RestClientTest(RemoteVehicleDetailsService::class)
class MyRestClientServiceTests(
@Autowired val service: RemoteVehicleDetailsService,
@Autowired val server: MockRestServiceServer) {
@Test
fun getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() {
server.expect(MockRestRequestMatchers.requestTo("https://example.com/greet/details"))
.andRespond(MockRestResponseCreators.withSuccess("hello", MediaType.TEXT_PLAIN))
val greeting = service.callRestService()
assertThat(greeting).isEqualTo("hello")
}
}
自动配置 Spring REST Docs 测试
你可以使用 @AutoConfigureRestDocs
注解来使用 Spring REST Docs 在你的测试中与 Mock MVC、REST Assured 或 WebTestClient 一起。
它消除了 Spring REST Docs 中 JUnit 扩展的需要。
@AutoConfigureRestDocs
可以用来覆盖默认输出目录(如果你使用 Maven 则是 target/generated-snippets
,如果你使用 Gradle 则是 build/generated-snippets
)。
它还可以用来配置出现在任何文档化 URI 中的主机、方案和端口。
自动配置 Spring REST Docs 测试 With Mock MVC
@AutoConfigureRestDocs
自定义用于测试 servlet 基础 web 应用程序的 MockMvc
bean 使用 Spring REST Docs。
你可以通过使用 @Autowired
注入它,并在你的测试中像使用 Mock MVC 和 Spring REST Docs 一样正常使用它,如下例所示:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
@WebMvcTest(UserController.class)
@AutoConfigureRestDocs
class MyUserDocumentationTests {
@Autowired
private MockMvcTester mvc;
@Test
void listUsers() {
assertThat(this.mvc.get().uri("/users").accept(MediaType.TEXT_PLAIN)).hasStatusOk()
.apply(document("list-users"));
}
}
如果你更喜欢使用 AssertJ 集成,MockMvcTester
也可以使用,如下例所示:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
@WebMvcTest(UserController.class)
@AutoConfigureRestDocs
class MyUserDocumentationTests {
@Autowired
private MockMvcTester mvc;
@Test
void listUsers() {
assertThat(this.mvc.get().uri("/users").accept(MediaType.TEXT_PLAIN)).hasStatusOk()
.apply(document("list-users"));
}
}
两者都使用相同的 MockMvc
实例,因此任何配置到它的配置都适用于两者。
如果你需要比 @AutoConfigureRestDocs
提供的属性更多的控制 Spring REST Docs 配置,你可以使用 RestDocsMockMvcConfigurationCustomizer
bean,如下例所示:
-
Java
-
Kotlin
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsMockMvcConfigurationCustomizer;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer;
import org.springframework.restdocs.templates.TemplateFormats;
@TestConfiguration(proxyBeanMethods = false)
public class MyRestDocsConfiguration implements RestDocsMockMvcConfigurationCustomizer {
@Override
public void customize(MockMvcRestDocumentationConfigurer configurer) {
configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
}
}
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsMockMvcConfigurationCustomizer
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer
import org.springframework.restdocs.templates.TemplateFormats
@TestConfiguration(proxyBeanMethods = false)
class MyRestDocsConfiguration : RestDocsMockMvcConfigurationCustomizer {
override fun customize(configurer: MockMvcRestDocumentationConfigurer) {
configurer.snippets().withTemplateFormat(TemplateFormats.markdown())
}
}
如果你想要为参数化输出目录创建 RestDocumentationResultHandler
bean。
自动配置调用 alwaysDo
与这个结果处理器,从而导致每次 MockMvc
调用自动生成默认片段。
以下示例展示了 RestDocumentationResultHandler
的定义:
-
Java
-
Kotlin
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;
@TestConfiguration(proxyBeanMethods = false)
public class MyResultHandlerConfiguration {
@Bean
public RestDocumentationResultHandler restDocumentation() {
return MockMvcRestDocumentation.document("{method-name}");
}
}
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation
import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler
@TestConfiguration(proxyBeanMethods = false)
class MyResultHandlerConfiguration {
@Bean
fun restDocumentation(): RestDocumentationResultHandler {
return MockMvcRestDocumentation.document("{method-name}")
}
}
自动配置 Spring REST Docs 测试 With WebTestClient
@AutoConfigureRestDocs
也可以与 WebTestClient
一起使用,用于测试反应性 web 应用程序。
你可以通过使用 @Autowired
注入它,并在你的测试中像使用 @WebFluxTest
和 Spring REST Docs 一样正常使用它,如下例所示:
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
@WebFluxTest
@AutoConfigureRestDocs
class MyUsersDocumentationTests {
@Autowired
private WebTestClient webTestClient;
@Test
void listUsers() {
this.webTestClient
.get().uri("/")
.exchange()
.expectStatus()
.isOk()
.expectBody()
.consumeWith(document("list-users"));
}
}
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation
import org.springframework.test.web.reactive.server.WebTestClient
@WebFluxTest
@AutoConfigureRestDocs
class MyUsersDocumentationTests(@Autowired val webTestClient: WebTestClient) {
@Test
fun listUsers() {
webTestClient
.get().uri("/")
.exchange()
.expectStatus()
.isOk
.expectBody()
.consumeWith(WebTestClientRestDocumentation.document("list-users"))
}
}
如果你需要比 @AutoConfigureRestDocs
提供的属性更多的控制 Spring REST Docs 配置,你可以使用 RestDocsWebTestClientConfigurationCustomizer
bean,如下例所示:
-
Java
-
Kotlin
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsWebTestClientConfigurationCustomizer;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer;
@TestConfiguration(proxyBeanMethods = false)
public class MyRestDocsConfiguration implements RestDocsWebTestClientConfigurationCustomizer {
@Override
public void customize(WebTestClientRestDocumentationConfigurer configurer) {
configurer.snippets().withEncoding("UTF-8");
}
}
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsWebTestClientConfigurationCustomizer
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer
@TestConfiguration(proxyBeanMethods = false)
class MyRestDocsConfiguration : RestDocsWebTestClientConfigurationCustomizer {
override fun customize(configurer: WebTestClientRestDocumentationConfigurer) {
configurer.snippets().withEncoding("UTF-8")
}
}
如果你想要为参数化输出目录创建 WebTestClientBuilderCustomizer
,你可以使用它来配置每个实体交换结果的消费者。
以下示例展示了如何定义此类 WebTestClientBuilderCustomizer
:
-
Java
-
Kotlin
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.web.reactive.server.WebTestClientBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
@TestConfiguration(proxyBeanMethods = false)
public class MyWebTestClientBuilderCustomizerConfiguration {
@Bean
public WebTestClientBuilderCustomizer restDocumentation() {
return (builder) -> builder.entityExchangeResultConsumer(document("{method-name}"));
}
}
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.boot.test.web.reactive.server.WebTestClientBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation
import org.springframework.test.web.reactive.server.WebTestClient
@TestConfiguration(proxyBeanMethods = false)
class MyWebTestClientBuilderCustomizerConfiguration {
@Bean
fun restDocumentation(): WebTestClientBuilderCustomizer {
return WebTestClientBuilderCustomizer { builder: WebTestClient.Builder ->
builder.entityExchangeResultConsumer(
WebTestClientRestDocumentation.document("{method-name}")
)
}
}
}
自动配置 Spring REST Docs 测试 With REST Assured
@AutoConfigureRestDocs
制作一个 RequestSpecification
bean,预配置为使用 Spring REST Docs,可供你的测试使用。
你可以通过使用 @Autowired
注入它,并在你的测试中像使用 REST Assured 和 Spring REST Docs 一样正常使用它,如下例所示:
-
Java
-
Kotlin
import io.restassured.specification.RequestSpecification;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.server.LocalServerPort;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.is;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureRestDocs
class MyUserDocumentationTests {
@Test
void listUsers(@Autowired RequestSpecification documentationSpec, @LocalServerPort int port) {
given(documentationSpec)
.filter(document("list-users"))
.when()
.port(port)
.get("/")
.then().assertThat()
.statusCode(is(200));
}
}
import io.restassured.RestAssured
import io.restassured.specification.RequestSpecification
import org.hamcrest.Matchers
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
import org.springframework.boot.test.web.server.LocalServerPort
import org.springframework.restdocs.restassured.RestAssuredRestDocumentation
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureRestDocs
class MyUserDocumentationTests {
@Test
fun listUsers(@Autowired documentationSpec: RequestSpecification?, @LocalServerPort port: Int) {
RestAssured.given(documentationSpec)
.filter(RestAssuredRestDocumentation.document("list-users"))
.`when`()
.port(port)["/"]
.then().assertThat()
.statusCode(Matchers.`is`(200))
}
}
如果你需要比 @AutoConfigureRestDocs
提供的属性更多的控制 Spring REST Docs 配置,可以使用 RestDocsRestAssuredConfigurationCustomizer
bean,如下例所示:
-
Java
-
Kotlin
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsRestAssuredConfigurationCustomizer;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.restdocs.restassured.RestAssuredRestDocumentationConfigurer;
import org.springframework.restdocs.templates.TemplateFormats;
@TestConfiguration(proxyBeanMethods = false)
public class MyRestDocsConfiguration implements RestDocsRestAssuredConfigurationCustomizer {
@Override
public void customize(RestAssuredRestDocumentationConfigurer configurer) {
configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
}
}
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsRestAssuredConfigurationCustomizer
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.restdocs.restassured.RestAssuredRestDocumentationConfigurer
import org.springframework.restdocs.templates.TemplateFormats
@TestConfiguration(proxyBeanMethods = false)
class MyRestDocsConfiguration : RestDocsRestAssuredConfigurationCustomizer {
override fun customize(configurer: RestAssuredRestDocumentationConfigurer) {
configurer.snippets().withTemplateFormat(TemplateFormats.markdown())
}
}
自动配置 Spring Web Services 测试
自动配置 Spring Web Services 客户端测试
你可以使用 @WebServiceClientTest
测试使用 Spring Web Services 项目调用 web 服务的应用程序。
默认情况下,它会配置一个 MockWebServiceServer
bean,并自动自定义你的 WebServiceTemplateBuilder
。
(关于在 Spring Boot 中使用 Web Services 的更多内容,见 Web Services。)
@WebServiceClientTest 启用的自动配置设置列表可在 附录中找到。
|
以下示例展示了 @WebServiceClientTest
注解的用法:
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.webservices.client.WebServiceClientTest;
import org.springframework.ws.test.client.MockWebServiceServer;
import org.springframework.xml.transform.StringSource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.ws.test.client.RequestMatchers.payload;
import static org.springframework.ws.test.client.ResponseCreators.withPayload;
@WebServiceClientTest(SomeWebService.class)
class MyWebServiceClientTests {
@Autowired
private MockWebServiceServer server;
@Autowired
private SomeWebService someWebService;
@Test
void mockServerCall() {
this.server
.expect(payload(new StringSource("<request/>")))
.andRespond(withPayload(new StringSource("<response><status>200</status></response>")));
assertThat(this.someWebService.test())
.extracting(Response::getStatus)
.isEqualTo(200);
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.webservices.client.WebServiceClientTest
import org.springframework.ws.test.client.MockWebServiceServer
import org.springframework.ws.test.client.RequestMatchers
import org.springframework.ws.test.client.ResponseCreators
import org.springframework.xml.transform.StringSource
@WebServiceClientTest(SomeWebService::class)
class MyWebServiceClientTests(@Autowired val server: MockWebServiceServer, @Autowired val someWebService: SomeWebService) {
@Test
fun mockServerCall() {
server
.expect(RequestMatchers.payload(StringSource("<request/>")))
.andRespond(ResponseCreators.withPayload(StringSource("<response><status>200</status></response>")))
assertThat(this.someWebService.test()).extracting(Response::status).isEqualTo(200)
}
}
自动配置 Spring Web Services 服务器测试
你可以使用 @WebServiceServerTest
测试使用 Spring Web Services 项目实现 web 服务的应用程序。
默认情况下,它会配置一个 MockWebServiceClient
bean,你可以使用它来调用你的 web 服务端点。
(关于在 Spring Boot 中使用 Web Services 的更多内容,见 Web Services。)
@WebServiceServerTest 启用的自动配置设置列表可在 附录中找到。
|
以下示例展示了 @WebServiceServerTest
注解的用法:
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.webservices.server.WebServiceServerTest;
import org.springframework.ws.test.server.MockWebServiceClient;
import org.springframework.ws.test.server.RequestCreators;
import org.springframework.ws.test.server.ResponseMatchers;
import org.springframework.xml.transform.StringSource;
@WebServiceServerTest(ExampleEndpoint.class)
class MyWebServiceServerTests {
@Autowired
private MockWebServiceClient client;
@Test
void mockServerCall() {
this.client
.sendRequest(RequestCreators.withPayload(new StringSource("<ExampleRequest/>")))
.andExpect(ResponseMatchers.payload(new StringSource("<ExampleResponse>42</ExampleResponse>")));
}
}
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.webservices.server.WebServiceServerTest
import org.springframework.ws.test.server.MockWebServiceClient
import org.springframework.ws.test.server.RequestCreators
import org.springframework.ws.test.server.ResponseMatchers
import org.springframework.xml.transform.StringSource
@WebServiceServerTest(ExampleEndpoint::class)
class MyWebServiceServerTests(@Autowired val client: MockWebServiceClient) {
@Test
fun mockServerCall() {
client
.sendRequest(RequestCreators.withPayload(StringSource("<ExampleRequest/>")))
.andExpect(ResponseMatchers.payload(StringSource("<ExampleResponse>42</ExampleResponse>")))
}
}
额外自动配置和切片
每个切片提供一个或多个 @AutoConfigure…
注解,这些注解定义了应该作为切片一部分包含的自动配置。
额外的自动配置可以在测试的基础上通过创建自定义 @AutoConfigure…
注解或通过将 @ImportAutoConfiguration
添加到测试中来添加,如下例所示:
-
Java
-
Kotlin
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration;
import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
@JdbcTest
@ImportAutoConfiguration(IntegrationAutoConfiguration.class)
class MyJdbcTests {
}
import org.springframework.boot.autoconfigure.ImportAutoConfiguration
import org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration
import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest
@JdbcTest
@ImportAutoConfiguration(IntegrationAutoConfiguration::class)
class MyJdbcTests
注意:不要使用常规的 @Import
注解导入自动配置,因为它们由 Spring Boot 以特定方式处理。
或者,额外的自动配置可以为任何使用切片注解的用例通过在 META-INF/spring
中存储的文件来添加,如下例所示:
com.example.IntegrationAutoConfiguration
在此示例中,com.example.IntegrationAutoConfiguration
在每个使用 @JdbcTest
注解的测试上启用。
提示:你可以在文件中使用 #
进行注释。
提示:切片或 @AutoConfigure…
注解可以这样自定义,只要它被 meta-annotated 为 @ImportAutoConfiguration
。
用户配置和切片
如果你 结构你的代码 在合理的方式,你的 @SpringBootApplication
类是 默认使用 作为测试的配置。
然后,重要的是不要在应用程序的主类中添加特定于某个功能的配置设置。
假设你正在使用 Spring Data MongoDB,你依赖于它的自动配置,并且你已经启用了审计。
你可以将你的 @SpringBootApplication
定义如下:
-
Java
-
Kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.config.EnableMongoAuditing;
@SpringBootApplication
@EnableMongoAuditing
public class MyApplication {
// ...
}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.data.mongodb.config.EnableMongoAuditing
@SpringBootApplication
@EnableMongoAuditing
class MyApplication {
// ...
}
因为此类是测试的源配置,任何切片测试实际上试图启用 Mongo 审计,这绝对不是你想要的。
推荐的方法是将该区域特定的配置移动到一个单独的 @Configuration
类,与你的应用程序在同一级别,如下例所示:
-
Java
-
Kotlin
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.EnableMongoAuditing;
@Configuration(proxyBeanMethods = false)
@EnableMongoAuditing
public class MyMongoConfiguration {
// ...
}
import org.springframework.context.annotation.Configuration
import org.springframework.data.mongodb.config.EnableMongoAuditing
@Configuration(proxyBeanMethods = false)
@EnableMongoAuditing
class MyMongoConfiguration {
// ...
}
注意:根据你的应用程序的复杂性,你可能有一个单独的 @Configuration
类用于你的自定义,或者每个领域区域一个类。
后一种方法允许你在某个测试中启用它,如果必要的话,使用 @Import
注解。
请参阅 此如何部分,了解何时可能希望为切片测试启用特定的 @Configuration
类。
测试切片排除 @Configuration
类从扫描。
例如,对于 @WebMvcTest
,以下配置不会在测试切片加载的应用程序上下文中包含给定的 WebMvcConfigurer
bean:
-
Java
-
Kotlin
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration(proxyBeanMethods = false)
public class MyWebConfiguration {
@Bean
public WebMvcConfigurer testConfigurer() {
return new WebMvcConfigurer() {
// ...
};
}
}
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
@Configuration(proxyBeanMethods = false)
class MyWebConfiguration {
@Bean
fun testConfigurer(): WebMvcConfigurer {
return object : WebMvcConfigurer {
// ...
}
}
}
以下配置将导致测试切片加载自定义的 WebMvcConfigurer
:
-
Java
-
Kotlin
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Component
public class MyWebMvcConfigurer implements WebMvcConfigurer {
// ...
}
import org.springframework.stereotype.Component
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
@Component
class MyWebMvcConfigurer : WebMvcConfigurer {
// ...
}
另一个混淆来源是类路径扫描。 假设,虽然你以合理的方式结构你的代码,但你需要扫描一个额外的包。 你的应用程序可能类似于以下代码:
-
Java
-
Kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan({ "com.example.app", "com.example.another" })
public class MyApplication {
// ...
}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.annotation.ComponentScan
@SpringBootApplication
@ComponentScan("com.example.app", "com.example.another")
class MyApplication {
// ...
}
这样做有效地覆盖了默认的组件扫描指令,副作用是扫描那些两个包,无论你选择哪个切片。
例如,@DataJpaTest
似乎突然扫描组件和用户配置。
再次,将自定义指令移动到一个单独的类是一个很好的解决方法。
提示:如果这不是一个选项,你可以创建一个 @SpringBootConfiguration
在测试层次结构中的某个地方,以便它被使用而不是默认的。
或者,你可以指定测试的来源,这会禁用查找默认配置的行为。
使用 Spock 测试 Spring Boot 应用程序
Spock 2.2 或更高版本可以用来测试 Spring Boot 应用程序。
为此,请在应用程序的构建中添加对 Spock 的 -groovy-4.0
版本的 spock-spring
模块的依赖。
spock-spring
将 Spring 的测试框架集成到 Spock 中。
请参阅 Spock 的 Spring 模块文档,了解更多细节。