本文为官方文档直译版本。原文链接
Spring Boot Testing中文文档
-
- 引言
- 测试范围依赖
- 测试 Spring 应用程序
- 测试 Spring Boot 应用程序
-
- 检测 Web 应用程序类型
- 检测测试配置
- 使用测试配置主方法
- 排除测试配置
- 使用应用程序参数
- 使用模拟环境进行测试
- 通过运行中的服务器进行测试
- 自定义 WebTestClient
- 使用 JMX
- 使用指标
- 使用跟踪
- 模拟和 Spying Beans
- 自动配置测试
- 自动配置 JSON 测试
- 自动配置的 Spring MVC 测试
- 自动配置 Spring WebFlux 测试
- 自动配置 Spring GraphQL 测试
- 自动配置 Data Cassandra 测试
- 自动配置Data Couchbase 测试
- 自动配置Data Elasticsearch 测试
- 自动配置Data JPA 测试
- 自动配置 JDBC 测试
- 自动配置Data JDBC 测试
- 自动配置Data R2DBC 测试
- 自动配置 jOOQ 测试
- 自动配置Data MongoDB 测试
- 自动配置Data Neo4j 测试
- 自动配置Data Redis 测试
- 自动配置Data LDAP 测试
- 自动配置 REST 客户端
- 自动配置 Spring REST Docs 测试
- 自动配置 Spring Web 服务测试
- 额外的自动配置和切片功能
- 用户配置和切片
- 使用 Spock 测试 Spring Boot 应用程序
- 测试容器
- 测试工具
引言
Spring Boot 提供了大量实用工具和注解,可在测试应用程序时提供帮助。测试支持由两个模块提供:spring-boot-test
包含核心项目,spring-boot-test-autoconfigure
支持测试的自动配置。
大多数开发人员使用 spring-boot-starter-test
“Starter”,它同时导入了 Spring Boot 测试模块以及 JUnit Jupiter、AssertJ、Hamcrest 和其他一些有用的库。
如果有使用 JUnit 4 的测试,可以使用 JUnit 5 的 vintage 引擎来运行它们。要使用 vintage 引擎,请添加对
junit-vintage-engine
的依赖,如下例所示:
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
hamcrest-core
排除在外,而使用 spring-boot-starter-test
中的 org.hamcrest:hamcrest
。
测试范围依赖
spring-boot-starter-test
“Starter”(在test``scope
内)包含以下提供的库:
- JUnit 5:Java 应用程序单元测试的事实标准。
- Spring Test 和 Spring Boot Test: 为 Spring Boot 应用程序提供实用程序和集成测试支持。
- AssertJ:流畅的断言库。
- Hamcrest: 一个匹配器对象库(也称为约束或谓词)。
- Mockito:一个 Java 模拟框架: 一个 Java 模拟框架。
- JSONassert: 一个 JSON 断言库。
- JsonPath:JSON 的 XPath: JSON 的 XPath。
- Awaitility:用于测试异步系统的库: 用于测试异步系统的库。
在编写测试时,我们通常会发现这些常用库非常有用。如果这些库不能满足您的需求,您可以自行添加其他测试依赖库。
测试 Spring 应用程序
依赖注入的一个主要优势是,它可以让你的代码更容易进行单元测试。您可以使用 new
操作符实例化对象,而无需涉及 Spring。您还可以使用模拟对象来代替真实的依赖关系。
通常情况下,你需要超越单元测试,开始集成测试(使用 Spring ApplicationContext
)。无需部署应用程序或连接其他基础架构就能执行集成测试是非常有用的。
Spring 框架包含一个专用测试模块,用于此类集成测试。您可以直接向 org.springframework:spring-test
声明依赖关系,或使用 spring-boot-starter-test
“Starter “将其临时引入。
如果你以前没有使用过 spring-test
模块,应该先阅读 Spring Framework 参考文档的相关章节。
测试 Spring Boot 应用程序
Spring Boot 应用程序是一个 Spring ApplicationContext
,因此除了通常使用普通 Spring 上下文进行测试外,不需要做任何特别的测试。
只有在使用
SpringApplication
创建上下文时,Spring Boot 的外部属性、日志和其他功能才会默认安装在上下文中。
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
(默认): 加载网络ApplicationContext
并提供模拟网络环境。使用此注解时,不会启动嵌入式服务器。如果classpath 上没有网络环境,该模式会透明地退回到创建普通的非网络ApplicationContext
。它可与@AutoConfigureMockMvc
或@AutoConfigureWebTestClient
结合使用,用于对网络应用程序进行基于模拟的测试。RANDOM_PORT
:加载WebServerApplicationContext
并提供真实的网络环境。嵌入式服务器会启动并监听一个随机端口。DEFINED_PORT
:加载WebServerApplicationContext
并提供真实的网络环境。嵌入式服务器将被启动,并监听一个已定义的端口(application.properties
)或默认的 8080 端口。NONE
: 使用 SpringApplication 加载 ApplicationContext,但不提供任何网络环境(模拟或其他)。
如果您的测试是
@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
属性:
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest(properties = "spring.main.web-application-type=reactive")
class MyWebFluxTests {
// ...
}
检测测试配置
如果您熟悉 Spring 测试框架,可能会习惯使用 @ContextConfiguration(classes=...)
来指定要加载的 Spring @Configuration
。另外,您可能经常在测试中使用嵌套的 @Configuration
类。
在测试 Spring Boot 应用程序时,通常不需要这样做。只要您没有明确定义,Spring Boot 的 @*Test
注解就会自动搜索您的主配置。
搜索算法会从包含测试的包开始往上搜索,直到找到注释为 @SpringBootApplication
或 @SpringBootConfiguration
的类为止。只要代码结构合理,通常就能找到主配置。
如果使用测试注解来测试应用程序的特定切片,则应避免在主方法的应用程序类上添加针对特定区域的配置设置。
@SpringBootApplication
的底层组件扫描配置定义了排除过滤器,用于确保切片工作符合预期。如果你在@SpringBootApplication
注释的类中使用了显式@ComponentScan
指令,请注意这些过滤器将被禁用。如果正在使用切片功能,则应重新定义它们。
如果要自定义主配置,可以使用嵌套的 @TestConfiguration
类。与嵌套的 @Configuration
类不同的是,嵌套的 @TestConfiguration
类是应用程序主配置的补充。
Spring 的测试框架会在测试之间缓存应用程序上下文。因此,只要你的测试共享相同的配置(无论配置是如何被发现的),加载上下文这一可能耗时的过程就只会发生一次。
使用测试配置主方法
通常情况下,@SpringBootTest
发现的测试配置将是你的主@SpringBootApplication
。在大多数结构良好的应用程序中,该配置类还将包括用于启动应用程序的主方法。
例如,以下是典型 Spring Boot 应用程序的常见代码模式:
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);
}
}
在上面的示例中,main
方法除了委托 SpringApplication.run
以外没有做任何其他事情。不过,也可以使用更复杂的 main
方法,在调用 SpringApplication.run
之前应用自定义功能。
例如,下面是一个更改横幅模式和设置附加配置文件的应用程序:
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);
}
}
由于main
方法中的自定义会影响生成的ApplicationContext
,所以你也可能想使用main
方法来创建测试中使用的ApplicationContext
。默认情况下,@SpringBootTest
不会调用主方法,而是直接使用类本身来创建 ApplicationContext
如果想改变这种行为,可以将 @SpringBootTest
的 useMainMethod
属性改为 UseMainMethod.ALWAYS
或 UseMainMethod.WHEN_AVAILABLE
。当设置为 ALWAYS
时,如果找不到主方法,测试就会失败。设置为 WHEN_AVAILABLE
时,如果主方法可用,则将使用该方法,否则将使用标准加载机制。
例如,下面的测试将调用 MyApplication
的主方法来创建 ApplicationContext
。如果主方法设置了附加配置文件,那么这些配置文件将在 ApplicationContext
启动时处于活动状态。
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() {
// ...
}
}
排除测试配置
如果你的应用程序使用了组件扫描(例如,如果你使用了 @SpringBootApplication
或 @ComponentScan
),你可能会发现只为特定测试创建的顶级配置类不小心被到处收集。
正如我们前面所看到的,@TestConfiguration
可用于测试的内部类,以自定义主要配置。@TestConfiguration
也可用于顶层类。这样做表示该类不应被扫描选中。然后,您可以在需要的地方显式导入该类,如下例所示:
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() {
// ...
}
}
如果直接使用
@ComponentScan
(即不通过@SpringBootApplication
),则需要注册TypeExcludeFilter
。详情请参见 Javadoc。
导入的
@TestConfiguration
比内类的@TestConfiguration
处理得更早,而且导入的@TestConfiguration
将在通过组件扫描发现的任何配置之前被处理。一般来说,这种排序上的差异不会产生明显的影响,但如果您依赖 bean 重载,则需要注意这一点。
使用应用程序参数
如果应用程序需要参数,可以让 @SpringBootTest
使用 args
属性注入参数。
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");
}
}
使用模拟环境进行测试
默认情况下,@SpringBootTest
不会启动服务器,而是为测试 Web 端点设置一个模拟环境。
使用 Spring MVC,我们可以使用 [MockMvc](https://docs.spring.io/spring-framework/reference/testing/spring-mvc-test-framework.html)
或 WebTestClient
查询网络端点,如下例所示:
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 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 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");
}
}
如果只想关注网络层而不想启动完整的
ApplicationContext
,可以考虑使用@WebMvcTest
代替。
通过 Spring WebFlux 端点,您可以使用 [WebTestClient](https://docs.spring.io/spring-framework/reference/testing/webtestclient.html)
,如下例所示:
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");
}
}
在模拟环境中进行测试通常比使用完整的 servlet 容器运行更快。不过,由于模拟发生在 Spring MVC 层,因此依赖于低层 servlet 容器行为的代码无法直接使用 MockMvc 进行测试。
例如,Spring Boot 的错误处理基于 servlet 容器提供的 “错误页面 “支持。这意味着,虽然您可以测试 MVC 层是否按预期抛出和处理异常,但却无法直接测试是否渲染了特定的自定义错误页面。如果需要测试这些较低层次的问题,可以按照下一节所述启动一个完全运行的服务器。
通过运行中的服务器进行测试
如果需要启动一个完整运行的服务器,建议使用随机端口。如果使用 @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
,每次测试运行时都会随机选择一个可用端口。
@LocalServerPort
注解可用于在测试中注入实际使用的端口。为方便起见,需要对已启动的服务器进行 REST 调用的测试可以额外 @Autowire
一个 WebTestClient
,它可以解析到运行服务器的相对链接,并带有专用的 API 来验证响应,如下例所示:
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");
}
}
通过使用
@AutoConfigureWebTestClient
对测试类进行注解,WebTestClient
还可以与模拟环境一起使用,从而无需运行服务器。
此设置需要在类路径上添加 spring-webflux
。如果不能或不愿添加 webflux
,Spring Boot 还提供了 TestRestTemplate
工具:
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");
}
}
自定义 WebTestClient
要自定义 WebTestClient
Bean,请配置 WebTestClientBuilderCustomizer
Bean。任何此类 Bean 都会被用于创建 WebTestClient
的 WebTestClient.Builder
调用。
使用 JMX
由于测试上下文框架会缓存上下文,因此默认情况下会禁用 JMX,以防止相同组件在同一域上注册。如果此类测试需要访问 MBeanServer
,请考虑将其也标记为 dirty:
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");
// ...
}
}
使用指标
在使用 @SpringBootTest
时,无论你的类路径如何,除了内存备份外,度量表注册表都不会自动配置。
如果需要将指标导出到不同的后端作为集成测试的一部分,请使用 @AutoConfigureObservability
进行注释。
使用跟踪
使用 @SpringBoot
Test 时,无论你的类路径如何,报告数据的跟踪组件都不会自动配置。
如果需要将这些组件作为集成测试的一部分,请使用 @AutoConfigureObservability
对测试进行注释。
如果你创建了自己的报告组件(例如自定义 SpanExporter
或 SpanHandler
),并且不想让它们在测试中激活,可以使用 @ConditionalOnEnabledTracing
注解来禁用它们。
模拟和 Spying Beans
运行测试时,有时需要在应用程序上下文中模拟某些组件。例如,您可能会在某个远程服务上设置一个门面,而该服务在开发过程中是不可用的。当您想模拟在真实环境中很难触发的故障时,模拟也很有用。
Spring Boot 包含一个 @MockBean
注解,可用于为 ApplicationContext
中的 Bean 定义 Mockito mock。您可以使用注解添加新的 Bean 或替换现有的 Bean 定义。该注解可直接用于测试类、测试中的字段或 @Configuration
类和字段。在字段上使用时,创建的模拟实例也会被注入。每次测试方法结束后,模拟 bean 都会自动重置。
如果您的测试使用了 Spring Boot 的测试注解之一(如
@SpringBootTest
),该功能就会自动启用。要在不同的安排下使用此功能,必须显式添加监听器,如下例所示:
import org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener;
import org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
@ContextConfiguration(classes = MyConfig.class)
@TestExecutionListeners({ MockitoTestExecutionListener.class, ResetMocksTestExecutionListener.class })
class MyTests {
// ...
}
下面的示例用一个模拟实现替换了现有的 RemoteService
Bean:
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.mock.mockito.MockBean;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
@SpringBootTest
class MyTests {
@Autowired
private Reverser reverser;
@MockBean
private RemoteService remoteService;
@Test
void exampleTest() {
given(this.remoteService.getValue()).willReturn("spring");
String reverse = this.reverser.getReverseValue(); // Calls injected RemoteService
assertThat(reverse).isEqualTo("gnirps");
}
}
@MockBean
不能用于模拟在应用程序上下文刷新期间执行的 Bean 行为。执行测试时,应用程序上下文刷新已经完成,来不及配置模拟行为。在这种情况下,我们建议使用@Bean
方法来创建和配置模拟。
此外,您还可以使用 @SpyBean
用 Mockito spy
封装任何现有 Bean。详情请参见 Javadoc。
Spring 的测试框架会在测试之间缓存应用程序上下文,并为共享相同配置的测试重用上下文,但
@MockBean
或@SpyBean
的使用会影响缓存键,这很可能会增加上下文的数量。
如果您使用
@SpyBean
来监视带有@Cacheable
方法的 Bean,而这些方法会通过名称引用参数,那么您的应用程序在编译时必须使用-parameters
。这样可以确保一旦 Bean 被监视,缓存基础架构就可以使用参数名称。
当您使用
@SpyBean
监视由 Spring 代理的 Bean 时,您可能需要在某些情况下移除 Spring 的代理,例如在使用given
或when
设置期望值时。请使用AopTestUtils.getTargetObject(yourProxiedSpy)
来移除代理。
自动配置测试
Spring Boot 的自动配置系统在应用程序中运行良好,但有时对测试来说可能有点太多。通常只加载测试应用程序 “片段 “所需的配置部分会有帮助。例如,您可能想测试 Spring MVC 控制器是否正确映射了 URL,而您不想在这些测试中涉及数据库调用,或者您可能想测试 JPA 实体,而您对这些测试运行时的 Web 层不感兴趣。
spring-boot-test-autoconfigure
模块包含大量注解,可用于自动配置此类 “切片”。每个注解的工作方式类似,都提供了一个用于加载 ApplicationContext
的 @...Test
注解,以及一个或多个用于自定义自动配置设置的 @AutoConfigure...annotation
注解。
每个片段都会将组件扫描限制在适当的组件上,并加载一组非常有限的自动配置类。如果需要排除其中一个,大多数
@...Test
注解都提供了一个excludeAutoConfiguration
属性。或者,您也可以使用@ImportAutoConfiguration#exclude
。
不支持在一个测试中使用多个
@...Test
注释来包含多个 “片段”。如果需要多个 “片段”,请选择其中一个@...Test
注释,然后手工添加其他 “片段 “的@AutoConfigure...annotations
。
也可以将
@AutoConfigure...
注解与标准的@SpringBootTest
注解结合使用。如果你对 “切分 “应用程序不感兴趣,但又想要一些自动配置的测试 Bean,那么就可以使用这种组合。
自动配置 JSON 测试
要测试对象 JSON 序列化和反序列化是否按预期运行,可以使用 @JsonTest
注解。@JsonTest
会自动配置可用的受支持 JSON 映射器,该映射器可以是以下库之一:
- Jackson
ObjectMapper
、任何@JsonComponent
Bean 和任何 Jackson 模块 - Gson
- Jsonb
@JsonTest
启用的自动配置列表见附录。
如果需要配置自动配置的元素,可以使用 @AutoConfigureJsonTesters
注解。
Spring Boot 包含基于 AssertJ 的帮助程序,可与 JSONAssert 和 JsonPath 库配合使用,检查 JSON 是否按预期显示。JacksonTester
、GsonTester
、JsonbTester
和 BasicJsonTester
类可分别用于 Jackson、Gson、Jsonb 和 Strings。使用 @JsonTest
时,测试类上的任何辅助字段都可以 @Autowired
。下面的示例展示了一个用于 Jackson 的测试类:
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");
}
}
JSON 辅助类也可直接用于标准单元测试。为此,如果不使用
@JsonTest
,请在@Before
方法中调用辅助类的initFields
方法。
如果您使用 Spring Boot 基于 AssertJ 的助手来断言给定 JSON 路径上的数字值,根据类型的不同,您可能无法使用 isEqualTo
。相反,您可以使用 AssertJ 的 satisfies 来断言该值符合给定条件。例如,下面的示例断言实际数字是一个接近 0.15
的浮点数值,偏移量为 0.01
。
@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)));
}
自动配置的 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
启用的自动配置设置列表见附录。
如果需要注册额外的组件(如 Jackson 模块),可以通过在测试中使用
@Import
来导入额外的配置类。
通常,@WebMvcTest
仅限于单个控制器,并与 @MockBean
结合使用,为所需的协作者提供模拟实现。
@WebMvcTest
还能自动配置 MockMvc
。Mock MVC 为快速测试 MVC 控制器提供了一种强大的方法,而无需启动完整的 HTTP 服务器。
你也可以在非
@WebMvcTest
(如@SpringBootTest
)中自动配置 MockMvc,方法是用@AutoConfigureMockMvc
对其进行注解。下面的示例使用了 MockMvc:
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.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.BDDMockito.given;
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;
@WebMvcTest(UserVehicleController.class)
class MyControllerTests {
@Autowired
private MockMvc mvc;
@MockBean
private UserVehicleService userVehicleService;
@Test
void testExample() throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda", "Civic"));
this.mvc.perform(get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andExpect(content().string("Honda Civic"));
}
}
如果需要配置自动配置的元素(例如,何时应用 servlet 过滤器),可以使用
@AutoConfigureMockMvc
注解中的属性。
如果使用 HtmlUnit 和 Selenium,自动配置还会提供一个 HtmlUnit WebClient
Bean 和/或 Selenium WebDriver
Bean。下面的示例使用了 HtmlUnit:
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.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.boot.test.mock.mockito.MockBean;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
@WebMvcTest(UserVehicleController.class)
class MyHtmlUnitTests {
@Autowired
private WebClient webClient;
@MockBean
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");
}
}
默认情况下,Spring Boot 会将
WebDriver
Bean 放在一个特殊的 “作用域 “中,以确保驱动程序在每次测试后退出,并注入一个新实例。如果不希望出现这种行为,可以在WebDriver
@Bean
定义中添加@Scope("singleton")
。
Spring Boot 创建的
WebDriver
作用域将取代任何用户定义的同名作用域。如果您定义了自己的WebDriver
作用域,可能会发现它在使用@WebMvcTest
时停止工作。
如果类路径上有 Spring Security,@WebMvcTest
也会扫描 WebSecurityConfigurer
Bean。你可以使用 Spring Security 的测试支持,而不是完全禁用此类测试的安全性。有关如何使用 Spring Security 的 MockMvc
支持的更多详情,请参阅 [howto.html](https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.testing.with-spring-security)
如何使用部分。
有时,仅编写 Spring MVC 测试是不够的;Spring Boot 可以帮助您使用实际服务器运行完整的端到端测试。
自动配置 Spring WebFlux 测试
要测试 Spring WebFlux 控制器是否按预期运行,可以使用 @WebFluxTest
注解。@WebFluxTest
会自动配置 Spring WebFlux 基础架构,并将扫描的 Bean 限制为 @Controller
、@ControllerAdvice
、@JsonComponent
、Converter
、GenericConverter
、WebFilter
和 WebFluxConfigurer
。使用 @WebFluxTest
注解时,常规的 @Component
和 @ConfigurationProperties
Bean 不会被扫描。@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
Bean。
@WebFluxTest 启用的自动配置列表见附录。
如果需要注册额外的组件(如 Jackson 模块),可以使用
@Import
在测试中导入额外的配置类。
通常,@WebFluxTest
仅限于单个控制器,并与 @MockBean
注解结合使用,为所需的协作者提供模拟实现。
@WebFluxTest
还能自动配置 [WebTestClient](https://docs.spring.io/spring-framework/reference/testing/webtestclient.html)
,这为快速测试 WebFlux
控制器提供了一种强大的方式,而无需启动完整的 HTTP 服务器。
你也可以在非
@WebFluxTest
(如@SpringBootTest
)中自动配置WebTestClient
,方法是用@AutoConfigureWebTestClient
对其进行注解。下面的示例展示了一个同时使用@WebFluxTest
和WebTestClient
的类:
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.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.mockito.BDDMockito.given;
@WebFluxTest(UserVehicleController.class)
class MyControllerTests {
@Autowired
private WebTestClient webClient;
@MockBean
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");
}
}
目前只有 WebFlux 应用程序支持这种设置,因为在模拟网络应用程序中使用
WebTestClient
只能与 WebFlux 配合使用。
@WebFluxTest
无法检测通过功能性 Web 框架注册的路由。若要在上下文中测试RouterFunction
Bean,可考虑使用@Import
或@SpringBootTest
自行导入RouterFunction
。
@WebFluxTest
无法检测注册为SecurityWebFilterChain
类型的@Bean
的自定义安全配置。要将其纳入测试,需要使用@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>
<!-- Unless already present in the 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")
// Unless already present in the implementation configuration
testImplementation("org.springframework.boot:spring-boot-starter-webflux")
}
该测试模块包含 GraphQlTester
。测试中会大量使用该测试器,因此请务必熟悉使用。GraphQlTester
有多种变体,Spring Boot 会根据测试类型自动配置它们:
ExecutionGraphQlServiceTester
在服务器端执行测试,没有客户端,也没有传输工具HttpGraphQlTester
使用连接到服务器的客户端执行测试,无论是否有实时服务器
通过 @GraphQlTest
注解,Spring Boot 可以帮助您测试 Spring GraphQL 控制器。@GraphQlTest
会自动配置 Spring GraphQL 基础架构,而不涉及任何传输或服务器。这将扫描的 Bean 限制为 @Controller
、RuntimeWiringConfigurer
、JsonComponent
、Converter
、GenericConverter
、DataFetcherExceptionResolver
、Instrumentation
和 GraphQlSourceBuilderCustomizer
。当使用 @GraphQlTest
注解时,常规的 @Component
和 @ConfigurationProperties
Bean 不会被扫描。@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
Bean。
@GraphQlTest
启用的自动配置列表见附录。
通常,@GraphQlTest
仅限于一组控制器,并与 @MockBean
注解结合使用,为所需的协作器提供模拟实现。
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!");
}
}
@SpringBootTest
测试是完全集成测试,涉及整个应用程序。使用随机端口或定义端口时,会配置一个实时服务器,并自动生成一个 HttpGraphQlTester
Bean,以便使用它来测试服务器。当配置了 MOCK 环境时,您也可以用 @AutoConfigureHttpGraphQlTester
对测试类进行注解,从而请求一个 HttpGraphQlTester
Bean:
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!");
}
}
自动配置 Data Cassandra 测试
您可以使用 @DataCassandraTest
测试 Cassandra 应用程序。默认情况下,它会配置 CassandraTemplate
、扫描 @Table
类并配置 Spring Data Cassandra 资源库。使用 @DataCassandraTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
Bean。(有关在 Spring Boot 中使用 Cassandra 的更多信息,请参阅 “data.html”)。
@DataCassandraTest
启用的自动配置设置列表见附录。
下面的示例展示了在 Spring Boot 中使用 Cassandra 测试的典型设置:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.cassandra.DataCassandraTest;
@DataCassandraTest
class MyDataCassandraTests {
@Autowired
private SomeRepository repository;
}
自动配置Data Couchbase 测试
您可以使用 @DataCouchbaseTest
测试 Couchbase
应用程序。默认情况下,它会配置 CouchbaseTemplate
或 ReactiveCouchbaseTemplate
、扫描 @Document
类并配置 Spring Data Couchbase 存储库。使用 @DataCouchbaseTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
Bean。(有关在 Spring Boot 中使用 Couchbase 的更多信息,请参阅本章前面的 “data.html”)。
@DataCouchbaseTest
启用的自动配置设置列表见附录。
下面的示例展示了在 Spring Boot 中使用 Couchbase 测试的典型设置:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.couchbase.DataCouchbaseTest;
@DataCouchbaseTest
class MyDataCouchbaseTests {
@Autowired
private SomeRepository repository;
// ...
}
自动配置Data Elasticsearch 测试
您可以使用 @DataElasticsearchTest
测试 Elasticsearch 应用程序。默认情况下,它会配置 ElasticsearchRestTemplate
、扫描 @Document
类并配置 Spring Data Elasticsearch 资源库。使用 @DataElasticsearchTest
注解时,不会扫描常规的 @Component
和 @ConfigurationPropertie
s Bean。@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
Bean。(有关在 Spring Boot 中使用 Elasticsearch 的更多信息,请参阅本章前面的 “data.html”)。
@DataElasticsearchTest
启用的自动配置设置列表见附录。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.elasticsearch.DataElasticsearchTest;
@DataElasticsearchTest
class MyDataElasticsearchTests {
@Autowired
private SomeRepository repository;
// ...
}
自动配置Data JPA 测试
您可以使用 @DataJpaTest
注解来测试 JPA 应用程序。默认情况下,它会扫描 @Entity
类并配置 Spring Data JPA 资源库。如果类路径上有嵌入式数据库,它也会配置一个。通过将 spring.jpa.show-sql
属性设置为 true
,默认情况下会记录 SQL 查询。可以使用注解的 showSql
属性禁用此功能。
使用 @DataJpaTest
注解时不会扫描常规 @Component
和 @ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
Bean。
@DataJpaTest
启用的自动配置设置列表见附录。
默认情况下,数据 JPA 测试是事务性的,并在每次测试结束时回滚。详情请参见 Spring Framework 参考文档中的相关章节。如果这不是你想要的,你可以为某个测试或整个类禁用事务管理,方法如下:
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 {
// ...
}
数据 JPA 测试还可以注入 [TestEntityManager](https://github.com/spring-projects/spring-boot/tree/v3.2.0/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestEntityManager.java)
Bean,它提供了标准 JPA EntityManager
的替代方案,是专门为测试设计的。
TestEntityManager
也可以通过添加@AutoConfigureTestEntityManager
自动配置到任何基于 Spring 的测试类中。这样做时,请确保您的测试在事务中运行,例如在测试类或方法中添加@Transactional
。
如果需要,还可以使用 JdbcTemplate
。下面的示例展示了 @DataJpaTest
注解的使用:
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");
}
}
内存嵌入式数据库通常非常适合测试,因为它们速度快,而且不需要安装。不过,如果您更喜欢针对真实数据库运行测试,则可以使用 @AutoConfigureTestDatabase
注解,如下例所示:
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 {
// ...
}
自动配置 JDBC 测试
@JdbcTest
与 @DataJpaTest
类似,但适用于只需要数据源而不使用 Spring Data JDBC 的测试。默认情况下,它会配置一个内存嵌入式数据库和一个 JdbcTemplate
。使用 @JdbcTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
Bean。
@JdbcTest
启用的自动配置列表见附录。
默认情况下,JDBC 测试是事务性的,会在每次测试结束时回滚。详情请参见 Spring Framework 参考文档中的相关章节。如果这不是你想要的,你可以禁用某个测试或整个类的事务管理,具体做法如下:
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 {
}
如果您希望您的测试针对真实数据库运行,您可以使用
@AutoConfigureTestDatabase
注解,方法与@DataJpaTest
相同。(请参阅 “自动配置的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 示例所示。
如果您希望您的测试针对真实数据库运行,您可以使用 @AutoConfigureTestDatabase
注解,方法与 @DataJpaTest
相同。(请参阅 “自动配置Data JPA 测试”)。
自动配置Data R2DBC 测试
@DataR2dbcTest
与 @DataJdbcTest
类似,但用于使用 Spring Data R2DBC 资源库的测试。默认情况下,它会配置一个内存嵌入式数据库、一个 R2dbcEntityTemplate
和 Spring Data R2DBC 资源库。使用 @DataR2dbcTest
注解时,不会扫描常规 @Component
和 @ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
Bean。
@DataR2dbcTest
启用的自动配置列表见附录。
默认情况下,Data R2DBC 测试不是事务性的。
如果您希望测试在真实数据库中运行,可以使用 @AutoConfigureTestDatabase
注解,其使用方法与 @DataJpaTest
相同。(请参阅 “自动配置Data JPA 测试”)。
自动配置 jOOQ 测试
使用 @JooqTest
的方式与 @JdbcTest
类似,但用于与 jOOQ 相关的测试。由于 jOOQ 在很大程度上依赖于与数据库模式相对应的基于 Java 的模式,因此会使用现有的 DataSource
。如果你想用内存数据库代替它,可以使用 @AutoConfigureTestDatabase
来覆盖这些设置。(使用 @JooqTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
Bean。
@JooqTest
启用的自动配置列表见附录。
@JooqTest
配置 DSLContext
。下面的示例展示了 @JooqTest
注解的使用:
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;
// ...
}
JOOQ 测试是事务性的,默认情况下会在每个测试结束时回滚。如果这不是你想要的,你可以禁用某个测试或整个测试类的事务管理,如 JDBC 示例所示。
自动配置Data MongoDB 测试
您可以使用 @DataMongoTest
测试 MongoDB 应用程序。默认情况下,它会配置 MongoTemplate
、扫描 @Document
类并配置 Spring Data MongoDB 存储库。使用 @DataMongoTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
Bean。(有关在 Spring Boot 中使用 MongoDB 的更多信息,请参阅 “data.html”)。
@DataMongoTest
启用的自动配置设置列表见附录。
下面的类显示了 @DataMongoTest
注解的使用情况:
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;
// ...
}
自动配置Data Neo4j 测试
你可以使用 @DataNeo4jTest
测试 Neo4j 应用程序。默认情况下,它会扫描 @Node
类,并配置 Spring Data Neo4j 资源库。使用 @DataNeo4jTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
Bean。(有关在 Spring Boot 中使用 Neo4J 的更多信息,请参阅 “data.html”)。
@DataNeo4jTest
启用的自动配置设置列表见附录。
下面的示例展示了在 Spring Boot 中使用 Neo4J 测试的典型设置:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;
@DataNeo4jTest
class MyDataNeo4jTests {
@Autowired
private SomeRepository repository;
// ...
}
默认情况下,Data Neo4j 测试是事务性的,并在每次测试结束时回滚。更多详情,请参阅 Spring Framework 参考文档中的相关章节。如果这不是你想要的,你可以禁用某个测试或整个类的事务管理,如下所示:
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 {
}
反应式访问不支持事务测试。如果使用这种风格,则必须如上所述配置
@DataNeo4jTest
测试。
自动配置Data Redis 测试
你可以使用 @DataRedisTest
测试 Redis 应用程序。默认情况下,它会扫描 @RedisHash
类并配置 Spring Data Redis 存储库。使用 @DataRedisTest
注解时,不会扫描常规的 @Component
和 @ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
Bean。(有关在 Spring Boot 中使用 Redis 的更多信息,请参阅 “data.html”)。
@DataRedisTest
启用的自动配置设置列表见附录。
下面的示例展示了 @DataRedisTest
注解的使用:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest;
@DataRedisTest
class MyDataRedisTests {
@Autowired
private SomeRepository repository;
// ...
}
自动配置Data LDAP 测试
您可以使用 @DataLdapTest
测试 LDAP 应用程序。默认情况下,它会配置内存中的嵌入式 LDAP(如果可用)、配置 LdapTemplate
、扫描 @Entry
类并配置 Spring Data LDAP 资源库。使用 @DataLdapTest
注解时,不会扫描常规 @Component
和 @ConfigurationProperties
Bean。@EnableConfigurationProperties
可用于包含 @ConfigurationProperties
Bean。(有关在 Spring Boot 中使用 LDAP 的更多信息,请参阅 “data.html”)。
@DataLdapTest
启用的自动配置设置列表见附录。
下面的示例展示了 @DataLdapTest
注解的使用:
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;
// ...
}
内存中的嵌入式 LDAP 通常对测试非常有效,因为它速度快,而且不需要安装任何开发人员。但是,如果您更喜欢针对真实 LDAP 服务器运行测试,则应排除嵌入式 LDAP 自动配置,如下例所示:
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
启用的自动配置设置列表见附录。
应使用 @RestClientTest
的 value
或 components
属性指定要测试的特定 Bean。
如果在被测 Bean 中使用 RestTemplateBuilder
,并且在构建 RestTemplate
时调用了 RestTemplateBuilder.rootUri(String rootUri)
,则应在 MockRestServiceServer
期望中省略根 URI,如下例所示:
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 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");
}
}
在被测 Bean 中使用 RestClient.Builder
时,或使用 RestTemplateBuilder
而不调用 rootUri(String rootURI)
时,必须在 MockRestServiceServer
期望中使用完整的 URI,如下例所示:
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");
}
}
自动配置 Spring REST Docs 测试
您可以使用 @AutoConfigureRestDocs
注解,在使用 Mock MVC、REST Assured 或 WebTestClient 的测试中使用 Spring REST Docs。它消除了对 Spring REST Docs中 JUnit 扩展的需求。
@AutoConfigureRestDocs
可用于覆盖默认输出目录(如果使用 Maven,则为 target/generated-snippets
;如果使用 Gradle,则为 build/generated-snippets
)。它还可用于配置出现在任何文档 URI 中的主机、方案和端口。
使用 Mock MVC 自动配置 Spring REST Docs测试
@AutoConfigureRestDocs
可自定义 MockMvc
Bean,以便在测试基于 servlet 的 Web 应用程序时使用 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.MockMvc;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(UserController.class)
@AutoConfigureRestDocs
class MyUserDocumentationTests {
@Autowired
private MockMvc mvc;
@Test
void listUsers() throws Exception {
this.mvc.perform(get("/users").accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andDo(document("list-users"));
}
}
如果您需要对 Spring REST 文档配置进行比 @AutoConfigureRestDocs
属性更多的控制,可以使用 RestDocsMockMvcConfigurationCustomizer
Bean,如下例所示:
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());
}
}
如果您想利用 Spring REST Docs对参数化输出目录的支持,可以创建一个 RestDocumentationResultHandler
Bean。自动配置会调用此结果处理程序的 alwaysDo
,从而使每次 MockMvc
调用都自动生成默认片段。下面的示例显示了一个 RestDocumentationResultHandler
的定义:
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}");
}
}
使用 WebTestClient 自动配置 Spring REST Docs测试
在测试反应式 Web 应用程序时,@AutoConfigureRestDocs
还可以与 WebTestClient
一起使用。您可以使用 @Autowired
注入它,并在测试中使用它,就像通常使用 @WebFluxTest
和 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.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"));
}
}
如果您需要对 Spring REST Docs配置进行比 @AutoConfigureRestDocs
属性更多的控制,可以使用 RestDocsWebTestClientConfigurationCustomizer
Bean,如下例所示:
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");
}
}
如果想利用 Spring REST Docs 对参数化输出目录的支持,可以使用 WebTestClientBuilderCustomizer
为每个实体交换结果配置一个消费者。下面的示例展示了这样一个 WebTestClientBuilderCustomizer
的定义:
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}"));
}
}
使用 REST Assured 自动配置 Spring REST Docs测试
@AutoConfigureRestDocs
使预设为使用 Spring REST Docs的 RequestSpecification
Bean 可供测试使用。您可以使用 @Autowired
注入该 Bean,并在测试中使用它,就像通常使用 REST Assured 和 Spring REST Docs 时那样,如下例所示:
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));
}
}
如果您需要对 Spring REST 文档配置进行比 @AutoConfigureRestDocs
属性更多的控制,则可以使用 RestDocsRestAssuredConfigurationCustomizer
Bean,如下例所示:
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());
}
}
自动配置 Spring Web 服务测试
自动配置 Spring Web 服务客户端测试
您可以使用 @WebServiceClientTest
测试使用 Spring Web 服务项目调用 Web 服务的应用程序。默认情况下,它会配置一个模拟 WebServiceServer
Bean,并自动自定义 WebServiceTemplateBuilder
。(有关使用 Spring Boot 的 Web 服务的更多信息,请参阅 “io.html”)。
@WebServiceClientTest
启用的自动配置设置列表见附录。
下面的示例展示了 @WebServiceClientTest
注解的使用:
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);
}
}
自动配置 Spring Web 服务服务器测试
您可以使用 @WebServiceServerTest
测试使用 Spring Web 服务项目实现 Web 服务的应用程序。默认情况下,它会配置一个 MockWebServiceClient
Bean,用于调用 Web 服务端点。(有关在 Spring Boot 中使用 Web 服务的更多信息,请参阅 “io.html”)。
@WebServiceServerTest
启用的自动配置设置列表见附录。
下面的示例展示了 @WebServiceServerTest
注解的使用:
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>")));
}
}
额外的自动配置和切片功能
每个片段都提供一个或多个 @AutoConfigure...
注解,即定义应作为片段一部分的自动配置。可通过创建自定义 @AutoConfigure...
注解或在测试中添加 @ImportAutoConfiguration
来逐个测试添加其他自动配置,如下例所示:
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
中存储的文件中注册这些配置,如下例所示:
META-INF/spring/org.springframework.boot.test.autoconfigure.jdbc.JdbcTest.imports
com.example.IntegrationAutoConfiguration
在此示例中,com.example.IntegrationAutoConfiguration
会在每个使用 @JdbcTest
注释的测试中启用。
您可以在此文件中使用带有 # 的注释。
只要使用
@ImportAutoConfiguration
对片段或@AutoConfigure...
注释进行元注解,就可以通过这种方式对其进行自定义。
用户配置和切片
如果你的代码结构合理,你的 @SpringBootApplication
类就会被默认用作测试的配置。
因此,重要的是不要在应用程序的主类中添加针对其特定功能区域的配置设置。
假设您使用的是 Spring Data MongoDB,您依赖于它的自动配置,并启用了审计功能。你可以将 @SpringBootApplication
定义如下:
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.config.EnableMongoAuditing;
@SpringBootApplication
@EnableMongoAuditing
public class MyApplication {
// ...
}
由于该类是测试的源配置,因此任何片段测试实际上都会尝试启用 Mongo 审计,这绝对不是你想要做的。推荐的方法是将特定区域的配置转移到与应用程序同级的单独 @Configuration
类中,如下例所示:
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.EnableMongoAuditing;
@Configuration(proxyBeanMethods = false)
@EnableMongoAuditing
public class MyMongoConfiguration {
// ...
}
根据应用程序的复杂程度,您可以为自定义设置设置一个
@Configuration
类,或者为每个域区设置一个类。后一种方法允许您在必要时使用@Import
注解在其中一个测试中启用它。有关何时需要为切片测试启用特定@Configuration
类的更多详情,请参阅本节。
测试片从扫描中排除 @Configuration
类。例如,在 @WebMvcTest
中,以下配置不会在测试片段加载的应用程序上下文中包含给定的 WebMvcConfigurer
Bean:
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() {
// ...
};
}
}
不过,下面的配置会导致测试片加载自定义 WebMvcConfigurer
。
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Component
public class MyWebMvcConfigurer implements WebMvcConfigurer {
// ...
}
另一个造成混乱的原因是类路径扫描。假设您以合理的方式编排代码,但需要扫描一个额外的软件包。您的应用程序可能类似于以下代码:
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan({ "com.example.app", "com.example.another" })
public class MyApplication {
// ...
}
这样做会有效地覆盖默认组件扫描指令,并产生扫描这两个包的副作用,而与您选择的片段无关。例如,@DataJpaTest
似乎会突然扫描应用程序的组件和用户配置。同样,将自定义指令移至单独的类是解决这一问题的好方法。
如果你不能这样做,可以在测试的层次结构中创建一个
@SpringBootConfiguration
来代替它。或者,你也可以为测试指定一个源,从而禁用查找默认源的行为。
使用 Spock 测试 Spring Boot 应用程序
Spock 2.2 或更高版本可用于测试 Spring Boot 应用程序。为此,请在应用程序的构建中添加对 -groovy-4.0
版本 Spock 的 spock-spring
模块的依赖关系。spock-spring
将 Spring 的测试框架集成到 Spock 中。更多详情,请参阅 Spock 的 Spring 模块文档。
测试容器
Testcontainers 库提供了一种管理在 Docker 容器内运行的服务的方法。它与 JUnit 集成,让您可以编写一个测试类,在任何测试运行之前启动容器。Testcontainers 对于编写与真实后端服务(如 MySQL、MongoDB、Cassandra 等)对话的集成测试特别有用。
Testcontainers 在 Spring Boot 测试中的使用方法如下:
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.boot.test.context.SpringBootTest;
@Testcontainers
@SpringBootTest
class MyIntegrationTests {
@Container
static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:5");
@Test
void myTest() {
// ...
}
}
这将在运行任何测试之前启动一个运行 Neo4j 的 docker 容器(如果本地运行 Docker)。在大多数情况下,您需要配置应用程序以连接到容器中运行的服务。
连接服务
服务连接是与任何远程服务的连接。Spring Boot 的自动配置可以获取服务连接的详细信息,并利用它们建立与远程服务的连接。这样做时,连接详细信息优先于任何与连接相关的配置属性。
使用 Testcontainers 时,通过在测试类中注释容器字段,可以为在容器中运行的服务自动创建连接详细信息。
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
@Testcontainers
@SpringBootTest
class MyIntegrationTests {
@Container
@ServiceConnection
static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:5");
@Test
void myTest() {
// ...
}
}
通过 @ServiceConnection
,上述配置允许应用程序中与 Neo4j 相关的 Bean 与运行在 Testcontainers 管理的 Docker 容器中的 Neo4j 通信。这是通过自动定义 Neo4jConnectionDetails
Bean 来实现的,Neo4j 自动配置会使用该 Bean,并覆盖任何与连接相关的配置属性。
您需要将
spring-boot-testcontainers
模块添加为测试依赖项,以便使用 Testcontainers 服务连接。
服务连接注解由在 spring.factories
中注册的 ContainerConnectionDetailsFactory
类处理。ContainerConnectionDetailsFactory
可根据特定容器子类或 Docker 映像名称创建 ConnectionDetails
Bean。
spring-boot-testcontainers
jar 中提供了以下服务连接工厂:
Connection Details | Matched on |
---|---|
ActiveMQConnectionDetails |
名为 “symptoma/activemq “的容器 |
CassandraConnectionDetails |
CassandraContainer 类型的容器 |
CouchbaseConnectionDetails |
CouchbaseContainer 类型的容器 |
ElasticsearchConnectionDetails |
ElasticsearchContainer 类型的容器 |
FlywayConnectionDetails |
JdbcDatabaseContainer 类型的容器 |
JdbcConnectionDetails |
JdbcDatabaseContainer 类型的容器 |
KafkaConnectionDetails |
KafkaContainer 或 RedpandaContainer 类型的容器 |
LiquibaseConnectionDetails |
JdbcDatabaseContainer 类型的容器 |
MongoConnectionDetails |
MongoDBContainer 类型的容器 |
Neo4jConnectionDetails |
Neo4jContainer 类型的容器 |
OtlpMetricsConnectionDetails |
名为 “otel/opentelemetry-collector-contrib” 的容器 |
OtlpTracingConnectionDetails |
名为 “otel/opentelemetry-collector-contrib” 的容器 |
PulsarConnectionDetails |
PulsarContainer 类型的容器 |
R2dbcConnectionDetails |
类型为 MariaDBContainer 、MSSQLServerContainer 、MySQLContainer 、OracleContainer 或 PostgreSQLContainer 的容器 |
RabbitConnectionDetails |
RabbitMQContainer 类型的容器 |
RedisConnectionDetails |
名为 “redis “的容器 |
ZipkinConnectionDetails |
名为 “openzipkin/zipkin “的容器 |
默认情况下,将为给定容器创建所有适用的连接详情 Bean。例如,
PostgreSQLContainer
将同时创建JdbcConnectionDetails
和R2dbcConnectionDetails
。
如果只想创建适用类型的子集,可以使用@ServiceConnection
的 type 属性。
默认情况下,Container.getDockerImageName()
用于获取用于查找连接详细信息的名称。只要 Spring Boot 能够获取 Container
的实例(如上例中使用静态字段的情况),该方法就能正常工作。
如果使用 @Bean
方法,Spring Boot 不会调用 bean 方法来获取 Docker 映像名称,因为这会导致急于初始化的问题。相反,Bean 方法的返回类型会被用来查找应使用的连接细节。只要您使用的是类型化容器,例如 Neo4jContainer
或 RabbitMQContainer
,这种方法就会起作用。如果您使用的是 GenericContainer
,例如 Redis,则此方法将停止工作,如下例所示:
import org.testcontainers.containers.GenericContainer;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;
@TestConfiguration(proxyBeanMethods = false)
public class MyRedisConfiguration {
@Bean
@ServiceConnection(name = "redis")
public GenericContainer<?> redisContainer() {
return new GenericContainer<>("redis:7");
}
}
Spring Boot 无法从 GenericContainer
中得知使用了哪个容器映像,因此必须使用 @ServiceConnection
的 name
属性来提供该提示。
您也可以使用 @ServiceConnection
的 name
属性来覆盖将使用的连接细节,例如在使用自定义映像时。如果你使用的是 Docker 映像 registry.mycompany.com/mirror/myredis
,你可以使用 @ServiceConnection(name="redis")
来确保创建 RedisConnectionDetails
。
动态属性
@DynamicPropertySource
是服务连接的一个略显冗长但也更灵活的替代方法。静态 @DynamicPropertySource
方法允许向 Spring Environment 添加动态属性值。
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
@Testcontainers
@SpringBootTest
class MyIntegrationTests {
@Container
static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:5");
@Test
void myTest() {
// ...
}
@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
}
}
上述配置允许应用程序中与 Neo4j 相关的 Bean 与运行在 Testcontainers 管理的 Docker 容器中的 Neo4j 通信。
测试工具
Spring-boot 中打包了一些测试实用类,它们在测试应用程序时非常有用。
ConfigDataApplicationContextInitializer
ConfigDataApplicationContextInitializer
是一个 ApplicationContextInitializer
,你可以将它应用于你的测试,以加载 Spring Boot application.properties
文件。当你不需要 @SpringBootTest
提供的全套功能时,可以使用它,如下例所示:
import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer;
import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration(classes = Config.class, initializers = ConfigDataApplicationContextInitializer.class)
class MyConfigFileTests {
// ...
}
仅使用
ConfigDataApplicationContextInitializer
并不支持@Value("${...}")
注入。它的唯一作用是确保将application.properties
文件加载到 Spring 的环境中。要获得@Value
支持,需要额外配置PropertySourcesPlaceholderConfigurer
或使用@SpringBootTest
自动配置。
TestPropertyValues
TestPropertyValues
可让您快速向 ConfigurableEnvironment
或 ConfigurableApplicationContext
添加属性。您可以使用 key=value
字符串调用它,如下所示:
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
class MyEnvironmentTests {
@Test
void testPropertySources() {
MockEnvironment environment = new MockEnvironment();
TestPropertyValues.of("org=Spring", "name=Boot").applyTo(environment);
assertThat(environment.getProperty("name")).isEqualTo("Boot");
}
}
OutputCapture
OutputCapture
是一个 JUnit 扩展,可用于捕获 System.out
和 System.err
输出。要使用它,请添加 @ExtendWith(OutputCaptureExtension.class)
并将 CapturedOutput 作为参数注入测试类构造函数或测试方法,如下所示:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import static org.assertj.core.api.Assertions.assertThat;
@ExtendWith(OutputCaptureExtension.class)
class MyOutputCaptureTests {
@Test
void testName(CapturedOutput output) {
System.out.println("Hello World!");
assertThat(output).contains("World");
}
}
TestRestTemplate
TestRestTemplate
是 Spring RestTemplate
的便捷替代品,在集成测试中非常有用。你可以获得一个普通模板或一个发送 Basic HTTP 身份验证(带用户名和密码)的模板。无论哪种情况,模板都是容错的。这意味着它不会在出现 4xx 和 5xx 错误时抛出异常,从而以测试友好的方式运行。相反,可以通过返回的 ResponseEntity 及其状态代码检测到此类错误。
TestRestTemplate
是 SpringRestTemplate
的便捷替代品,在集成测试中非常有用。你可以获得一个普通模板或一个发送 Basic HTTP 身份验证(带用户名和密码)的模板。无论哪种情况,模板都是容错的。这意味着它不会在出现 4xx 和 5xx 错误时抛出异常,从而以测试友好的方式运行。相反,可以通过返回的 ResponseEntity 及其状态代码检测到此类错误。
建议使用 Apache HTTP 客户端(5.1 或更高版本),但并非必须。如果您的类路径上有 Apache HTTP 客户端,TestRestTemplate
会对客户端进行适当配置。如果使用的是 Apache HTTP 客户端,则会启用一些额外的测试友好功能:
- 不跟踪重定向(因此可以断言响应位置)。
- 忽略 Cookie(因此模板是无状态的)。
TestRestTemplate
可直接在集成测试中实例化,如下例所示:
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
class MyTests {
private final TestRestTemplate template = new TestRestTemplate();
@Test
void testRequest() {
ResponseEntity<String> headers = this.template.getForEntity("https://myhost.example.com/example", String.class);
assertThat(headers.getHeaders().getLocation()).hasHost("other.example.com");
}
}
另外,如果使用带有 WebEnvironment.RANDOM_PORT
或 WebEnvironment.DEFINED_PORT
的 @SpringBootTest
注解,就可以注入一个完全配置好的 TestRestTemplate
并开始使用。如有必要,还可通过 RestTemplateBuilder
Bean 进行其他自定义。任何未指定主机和端口的 URL 都会自动连接到嵌入式服务器,如下例所示:
import java.time.Duration;
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.context.TestConfiguration;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MySpringBootTests {
@Autowired
private TestRestTemplate template;
@Test
void testRequest() {
HttpHeaders headers = this.template.getForEntity("/example", String.class).getHeaders();
assertThat(headers.getLocation()).hasHost("other.example.com");
}
@TestConfiguration(proxyBeanMethods = false)
static class RestTemplateBuilderConfiguration {
@Bean
RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder().setConnectTimeout(Duration.ofSeconds(1))
.setReadTimeout(Duration.ofSeconds(1));
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/195194.html