测试 Spring Boot 应用程序

Spring Boot 应用程序是 SpringApplicationContext,因此除了您通常使用普通 Spring 上下文所做的作之外,无需做任何非常特别的事情来测试它。spring-doc.cadn.net.cn

默认情况下,Spring Boot 的外部属性、日志记录和其他功能才会安装在上下文中,前提是使用SpringApplication创建它。

Spring Boot 提供了一个@SpringBootTest注释,可用作标准的替代方案spring-test @ContextConfiguration当您需要 Spring Boot 功能时,注释。 注释的工作原理是创建 ApplicationContext通过SpringApplication. 除了@SpringBootTest还提供了许多其他注释,用于测试应用程序的更具体切片spring-doc.cadn.net.cn

如果您使用的是 JUnit 4,请不要忘记同时添加@RunWith(SpringRunner.class)否则将忽略注释。 如果您使用的是 JUnit 5,则无需添加等效的@ExtendWith(SpringExtension.class)@SpringBootTest和另一个@…​Test注释已经用它进行了注释。

默认情况下,@SpringBootTest不会启动服务器。 您可以使用webEnvironment属性@SpringBootTest要进一步优化测试的运行方式,请执行以下作:spring-doc.cadn.net.cn

如果您的测试是@Transactional,默认情况下,它会在每个测试方法的末尾回滚事务。 但是,由于将这种安排与RANDOM_PORTDEFINED_PORT隐式地提供了一个真正的 servlet 环境,HTTP 客户端和服务器在单独的线程中运行,因此在单独的事务中运行。 在这种情况下,在服务器上启动的任何事务都不会回滚。
@SpringBootTestwebEnvironment = WebEnvironment.RANDOM_PORT如果应用程序为管理服务器使用不同的端口,则还将在单独的随机端口上启动管理服务器。

检测 Web 应用程序类型

如果 Spring MVC 可用,则配置基于 MVC 的常规应用程序上下文。 如果您只有 Spring WebFlux,我们将检测到它并配置基于 WebFlux 的应用程序上下文。spring-doc.cadn.net.cn

如果两者都存在,则 Spring MVC 优先。 如果要在此方案中测试响应式 Web 应用程序,则必须将spring.main.web-application-type财产:spring-doc.cadn.net.cn

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=…​)以指定哪个弹簧@Configuration加载。 或者,您可能经常使用 nested@Configuration类。spring-doc.cadn.net.cn

在测试 Spring Boot 应用程序时,通常不需要这样做。 Spring Boot 的@*Test注释会在未显式定义主配置时自动搜索主配置。spring-doc.cadn.net.cn

搜索算法从包含测试的包开始工作,直到找到一个用@SpringBootApplication@SpringBootConfiguration. 只要您以合理的方式构建代码,通常会找到您的主要配置。spring-doc.cadn.net.cn

如果使用测试注释来测试应用程序的更具体切片,则应避免添加特定于主方法的应用程序类上特定区域的配置设置。spring-doc.cadn.net.cn

的底层组件扫描配置@SpringBootApplication定义用于确保切片按预期工作的排除过滤器。 如果您使用显式@ComponentScan指令@SpringBootApplication-annotated 类,请注意这些过滤器将被禁用。 如果使用切片,则应重新定义它们。spring-doc.cadn.net.cn

如果要自定义主配置,可以使用嵌套的@TestConfiguration类。 与嵌套的@Configuration类,它将用于代替应用程序的主要配置,一个嵌套的@TestConfigurationclass 是除应用程序的主要配置之外使用的。spring-doc.cadn.net.cn

Spring 的测试框架在测试之间缓存应用程序上下文。 因此,只要您的测试共享相同的配置(无论它是如何发现的),加载上下文的潜在耗时过程只发生一次。

使用测试配置主方法

通常,由@SpringBootTest将是你的主要@SpringBootApplication. 在大多数结构良好的应用程序中,此配置类还将包括main用于启动应用程序的方法。spring-doc.cadn.net.cn

例如,以下是典型 Spring Boot 应用程序的非常常见的代码模式:spring-doc.cadn.net.cn

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…​). 但是,有可能有一个更复杂的main在调用之前应用自定义的方法SpringApplication.run(Class, String…​).spring-doc.cadn.net.cn

例如,这是一个更改横幅模式并设置其他配置文件的应用程序:spring-doc.cadn.net.cn

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方法,而是直接使用类本身来创建ApplicationContextspring-doc.cadn.net.cn

如果要更改此行为,可以更改useMainMethod属性@SpringBootTestSpringBootTest.UseMainMethod.ALWAYSSpringBootTest.UseMainMethod.WHEN_AVAILABLE. 当设置为ALWAYS,如果没有,则测试将失败main方法可以找到。 当设置为WHEN_AVAILABLEmain如果可用,则使用方法,否则将使用标准加载机制。spring-doc.cadn.net.cn

例如,以下测试将调用main方法MyApplication为了创建ApplicationContext. 如果 main 方法设置了额外的配置文件,那么当ApplicationContext开始。spring-doc.cadn.net.cn

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),您可能会发现仅为特定测试创建的顶级配置类在任何地方都被意外地选中。spring-doc.cadn.net.cn

正如我们之前所看到的,@TestConfiguration可用于测试的内部类,以自定义主配置。@TestConfiguration也可以在顶级类上使用。这样做表示不应通过扫描来选取该类。 然后,您可以在需要的地方显式导入类,如以下示例所示:spring-doc.cadn.net.cn

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属性。spring-doc.cadn.net.cn

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-doc.cadn.net.cn

使用 Spring MVC,我们可以使用MockMvc. 提供三种集成:spring-doc.cadn.net.cn

以下示例展示了可用的集成:spring-doc.cadn.net.cn

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如以下示例所示:spring-doc.cadn.net.cn

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 层,因此无法直接使用 MockMvc 测试依赖于较低级别 servlet 容器行为的代码。spring-doc.cadn.net.cn

例如,Spring Boot 的错误处理基于 servlet 容器提供的“错误页面”支持。 这意味着,虽然您可以按预期测试 MVC 层引发和处理异常,但无法直接测试是否呈现了特定的自定义错误页。 如果需要测试这些较低级别的问题,可以启动完全运行的服务器,如下一节所述。spring-doc.cadn.net.cn

使用正在运行的服务器进行测试

如果您需要启动一个完全运行的服务器,我们建议您使用随机端口。 如果您使用@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT),则每次运行测试时都会随机选择可用端口。spring-doc.cadn.net.cn

@LocalServerPort注释可用于将实际使用的端口注入到测试中。 为方便起见,需要对已启动服务器进行 REST 调用的测试还可以自动连接WebTestClient,它解析到正在运行的服务器的相对链接,并附带一个用于验证响应的专用 API,如以下示例所示:spring-doc.cadn.net.cn

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设备:spring-doc.cadn.net.cn

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

要自定义WebTestClientbean,配置一个WebTestClientBuilderCustomizer豆。 任何此类 bean 都使用WebTestClient.Builder用于创建WebTestClient.spring-doc.cadn.net.cn

使用 JMX

由于测试上下文框架缓存上下文,因此默认情况下禁用 JMX 以防止相同的组件在同一域上注册。 如果此类测试需要访问MBeanServer,也可以考虑将其标记为脏:spring-doc.cadn.net.cn

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")
		// ...
	}

}

使用观测值

使用指标

无论您的类路径如何,在使用@SpringBootTest.spring-doc.cadn.net.cn

如果您需要在集成测试中将指标导出到其他后端,请使用@AutoConfigureObservability.spring-doc.cadn.net.cn

如果使用@AutoConfigureObservability,它会自动配置内存中的MeterRegistry. 不支持在切片测试中导出数据,并支持@AutoConfigureObservability注解。spring-doc.cadn.net.cn

使用跟踪

无论您的类路径如何,在使用@SpringBootTest.spring-doc.cadn.net.cn

如果您需要这些组件作为集成测试的一部分,请使用@AutoConfigureObservability.spring-doc.cadn.net.cn

如果您创建了自己的报告组件(例如,自定义SpanExporterbrave.handler.SpanHandler)并且您不希望它们在测试中处于活动状态,则可以使用@ConditionalOnEnabledTracing注释来禁用它们。spring-doc.cadn.net.cn

如果使用@AutoConfigureObservability,它会自动配置无作Tracer. 不支持在切片测试中导出数据,并支持@AutoConfigureObservability注解。spring-doc.cadn.net.cn

模拟和间谍豆子

运行测试时,有时需要模拟应用程序上下文中的某些组件。 例如,您可能在某些远程服务上有一个在开发过程中不可用的外观。 当您想要模拟在真实环境中可能难以触发的故障时,模拟也很有用。spring-doc.cadn.net.cn

Spring 框架包括一个@MockitoBean注释,可用于为 bean 中的 bean 定义 Mockito 模拟ApplicationContext. 此外@MockitoSpyBean可用于定义 Mockito 间谍。 在 Spring Framework 文档中了解有关这些功能的更多信息。spring-doc.cadn.net.cn

自动配置测试

Spring Boot 的自动配置系统适用于应用程序,但有时对于测试来说可能有点太多了。 仅加载测试应用程序的“切片”所需的配置部分通常会有所帮助。 例如,您可能想要测试 Spring MVC 控制器是否正确映射 URL,并且您不想在这些测试中涉及数据库调用,或者您可能想要测试 JPA 实体,并且在这些测试运行时您对 Web 层不感兴趣。spring-doc.cadn.net.cn

spring-boot-test-autoconfigure模块包含许多注释,可用于自动配置此类“切片”。 它们中的每一个都以类似的方式工作,提供一个@…​Test加载ApplicationContext以及一个或多个@AutoConfigure…​可用于自定义自动配置设置的注释。spring-doc.cadn.net.cn

每个切片将组件扫描限制为适当的组件,并加载一组非常有限的自动配置类。 如果您需要排除其中之一,大多数@…​Test注释提供excludeAutoConfiguration属性。 或者,您可以使用@ImportAutoConfiguration#exclude.
使用多个@…​Test不支持在一个测试中使用注释。 如果您需要多个“切片”,请选择其中一个@…​Test注释,并包含@AutoConfigure…​手工注释其他“切片”。
也可以使用@AutoConfigure…​标注与标准@SpringBootTest注解。 如果您对“切片”应用程序不感兴趣,但想要一些自动配置的测试 Bean,则可以使用此组合。

自动配置的 JSON 测试

要测试对象 JSON 序列化和反序列化是否按预期工作,您可以使用@JsonTest注解。@JsonTest自动配置可用的受支持的 JSON 映射器,它可以是以下库之一:spring-doc.cadn.net.cn

启用的自动配置列表@JsonTest可以在附录中找到

如果您需要配置自动配置的元素,可以使用@AutoConfigureJsonTesters注解。spring-doc.cadn.net.cn

Spring Boot 包括基于 AssertJ 的帮助程序,可与 JSONAssert 和 JsonPath 库配合使用,以检查 JSON 是否按预期显示。 这JacksonTester,GsonTester,JsonbTesterBasicJsonTester类可以分别用于 Jackson、Gson、Jsonb 和 Strings。测试类上的任何辅助字段都可以是@Autowired使用时@JsonTest. 以下示例显示了 Jackson 的测试类:spring-doc.cadn.net.cn

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 帮助程序类也可以直接在标准单元测试中使用。为此,请调用initFields方法的@BeforeEach方法,如果不使用@JsonTest.

如果您使用 Spring Boot 的基于 AssertJ 的帮助程序在给定 JSON 路径上断言数字值,则可能无法使用isEqualTo取决于类型。相反,您可以使用 AssertJ 的satisfies断言该值与给定条件匹配。例如,以下示例断言实际数字是接近0.150.01.spring-doc.cadn.net.cn

	@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 测试

启用的自动配置设置列表@WebMvcTest可以在附录中找到
如果您需要注册额外的组件,例如 JacksonModule,您可以使用以下命令导入其他配置类@Import在你的测试中。

经常@WebMvcTest仅限于单个控制器,并与@MockitoBean为所需的协作者提供模拟实现。spring-doc.cadn.net.cn

@WebMvcTest还自动配置MockMvc. Mock MVC 提供了一种快速测试 MVC 控制器的强大方法,而无需启动完整的 HTTP 服务器。 如果 AssertJ 可用,则由MockMvcTester也是自动配置的。spring-doc.cadn.net.cn

您还可以自动配置MockMvcMockMvcTester在非@WebMvcTest(例如@SpringBootTest),通过用@AutoConfigureMockMvc. 以下示例使用MockMvcTester:
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,则自动配置还会提供一个 HtmlUnitWebClientbean 和/或 SeleniumWebDriver豆。 以下示例使用 HtmlUnit:spring-doc.cadn.net.cn

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 将WebDriverbean 在一个特殊的“作用域”中,以确保驱动程序在每次测试后退出并注入一个新实例。 如果您不希望此行为,可以将@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)给你的WebDriver @Bean定义。
webDriverSpring Boot 创建的范围将替换任何用户定义的同名范围。 如果您定义自己的webDriverscope 你可能会发现它在使用@WebMvcTest.

如果类路径上有 Spring Security,@WebMvcTest也会扫描WebSecurityConfigurer豆。 您可以使用 Spring Security 的测试支持,而不是完全禁用此类测试的安全性。 有关如何使用 Spring Security 的MockMvc可以在此 Testing With Spring Security “作指南”部分找到支持。spring-doc.cadn.net.cn

有时编写 Spring MVC 测试是不够的;Spring Boot 可以帮助您使用实际服务器运行完整的端到端测试

自动配置的 Spring WebFlux 测试

要测试 Spring WebFlux 控制器是否按预期工作,您可以使用@WebFluxTest注解。@WebFluxTest自动配置 Spring WebFlux 基础设施并将扫描的 bean 限制为@Controller,@ControllerAdvice,@JsonComponent,Converter,GenericConverterWebFluxConfigurer. 定期@Component@ConfigurationProperties@WebFluxTest注释。@EnableConfigurationProperties可用于包含@ConfigurationProperties豆。spring-doc.cadn.net.cn

启用的自动配置列表@WebFluxTest可以在附录中找到
如果您需要注册额外的组件,例如 JacksonModule,您可以使用以下命令导入其他配置类@Import在你的测试中。

经常@WebFluxTest仅限于单个控制器,并与@MockitoBean注释,为所需的协作者提供模拟实现。spring-doc.cadn.net.cn

@WebFluxTest还自动配置WebTestClient,它提供了一种快速测试 WebFlux 控制器的强大方法,而无需启动完整的 HTTP 服务器。spring-doc.cadn.net.cn

您还可以自动配置WebTestClient在非@WebFluxTest(例如@SpringBootTest),通过用@AutoConfigureWebTestClient. 以下示例显示了同时使用@WebFluxTestWebTestClient:
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 应用程序支持,因为使用WebTestClient在模拟的 Web 应用程序中,目前仅适用于 WebFlux。
@WebFluxTest无法检测通过功能 Web 框架注册的路由。 用于测试RouterFunctionbean 中,请考虑导入RouterFunction使用@Import或通过使用@SpringBootTest.
@WebFluxTest无法检测注册为@Bean类型SecurityWebFilterChain. 要将其包含在测试中,您需要使用@Import或通过使用@SpringBootTest.
有时编写 Spring WebFlux 测试是不够的;Spring Boot 可以帮助您使用实际服务器运行完整的端到端测试

自动配置的 Spring GraphQL 测试

Spring GraphQL 提供了一个专用的测试支持模块;您需要将其添加到您的项目中:spring-doc.cadn.net.cn

专家
<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>
Gradle
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 将根据测试类型自动配置它们:spring-doc.cadn.net.cn

Spring Boot 可帮助您使用@GraphQlTest注解。@GraphQlTest自动配置 Spring GraphQL 基础设施,不涉及任何传输或服务器。 这会将扫描的 bean 限制为@Controller,RuntimeWiringConfigurer,JsonComponent,Converter,GenericConverter,DataFetcherExceptionResolver,InstrumentationGraphQlSourceBuilderCustomizer. 定期@Component@ConfigurationProperties@GraphQlTest注释。@EnableConfigurationProperties可用于包含@ConfigurationProperties豆。spring-doc.cadn.net.cn

启用的自动配置列表@GraphQlTest可以在附录中找到

经常@GraphQlTest仅限于一组控制器,并与@MockitoBean注释,为所需的协作者提供模拟实现。spring-doc.cadn.net.cn

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测试是完全集成测试,涉及整个应用程序。 使用随机或定义的端口时,将配置实时服务器,并配置HttpGraphQlTesterBean 是自动贡献的,因此您可以使用它来测试您的服务器。 配置 MOCK 环境后,您还可以请求HttpGraphQlTesterbean 通过使用@AutoConfigureHttpGraphQlTester:spring-doc.cadn.net.cn

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!")
	}
}

自动配置的数据 Cassandra 测试

您可以使用@DataCassandraTest来测试 Cassandra 应用程序。默认情况下,它配置了一个CassandraTemplate,扫描@Table类,并配置 Spring Data Cassandra 存储库。 定期@Component@ConfigurationProperties@DataCassandraTest注释。@EnableConfigurationProperties可用于包含@ConfigurationProperties豆。 (有关将 Cassandra 与 Spring Boot 一起使用的更多信息,请参阅 Cassandraspring-doc.cadn.net.cn

启用的自动配置设置列表@DataCassandraTest可以在附录中找到

以下示例显示了在 Spring Boot 中使用 Cassandra 测试的典型设置:spring-doc.cadn.net.cn

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 应用程序。默认情况下,它配置了一个CouchbaseTemplateReactiveCouchbaseTemplate,扫描@Document类,并配置 Spring Data Couchbase 存储库。 定期@Component@ConfigurationProperties@DataCouchbaseTest注释。@EnableConfigurationProperties可用于包含@ConfigurationProperties豆。 (有关将 Couchbase 与 Spring Boot 一起使用的更多信息,请参阅本章前面的 Couchbasespring-doc.cadn.net.cn

启用的自动配置设置列表@DataCouchbaseTest可以在附录中找到

以下示例显示了在 Spring Boot 中使用 Couchbase 测试的典型设置:spring-doc.cadn.net.cn

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) {

	// ...

}

自动配置的数据 Elasticsearch 测试

您可以使用@DataElasticsearchTest以测试 Elasticsearch 应用程序。 默认情况下,它配置一个ElasticsearchTemplate,扫描@Document类,并配置 Spring Data Elasticsearch 存储库。 定期@Component@ConfigurationProperties@DataElasticsearchTest注释。@EnableConfigurationProperties可用于包含@ConfigurationProperties豆。 (有关将 Elasticsearch 与 Spring Boot 一起使用的更多信息,请参阅本章前面的 Elasticsearchspring-doc.cadn.net.cn

启用的自动配置设置列表@DataElasticsearchTest可以在附录中找到

以下示例显示了在 Spring Boot 中使用 Elasticsearch 测试的典型设置:spring-doc.cadn.net.cn

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) {

	// ...

}

自动配置的数据 JPA 测试

您可以使用@DataJpaTest注释来测试 JPA 应用程序。 默认情况下,它会扫描@Entity类并配置 Spring Data JPA 存储库。 如果类路径上有一个嵌入式数据库可用,它也会配置一个。 默认情况下,通过将spring.jpa.show-sql属性设置为true. 可以使用showSql属性。spring-doc.cadn.net.cn

启用的自动配置设置列表@DataJpaTest可以在附录中找到

默认情况下,数据 JPA 测试是事务性的,并在每次测试结束时回滚。 有关更多详细信息,请参阅 Spring Framework 参考文档中的相关部分。 如果这不是您想要的,您可以禁用测试或整个类的事务管理,如下所示:spring-doc.cadn.net.cn

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 {

	// ...

}

数据 JPA 测试还可以注入一个TestEntityManagerbean,它提供了标准 JPA 的替代方案EntityManager这是专门为测试而设计的。spring-doc.cadn.net.cn

TestEntityManager也可以通过添加@AutoConfigureTestEntityManager. 这样做时,请确保您的测试在事务中运行,例如通过添加@Transactional在测试类或方法上。

一个JdbcTemplate如果您需要,也可以使用。 以下示例显示了@DataJpaTest使用中的注释:spring-doc.cadn.net.cn

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注释,如以下示例所示:spring-doc.cadn.net.cn

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. 定期@Component@ConfigurationProperties@JdbcTest注释。@EnableConfigurationProperties可用于包含@ConfigurationProperties豆。spring-doc.cadn.net.cn

启用的自动配置列表@JdbcTest可以在附录中找到

默认情况下,JDBC 测试是事务性的,并在每次测试结束时回滚。 有关更多详细信息,请参阅 Spring Framework 参考文档中的相关部分。 如果这不是您想要的,您可以禁用测试或整个类的事务管理,如下所示:spring-doc.cadn.net.cn

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

如果您希望测试针对真实数据库运行,则可以使用@AutoConfigureTestDatabase注释的方式与@DataJpaTest. (请参阅自动配置的数据 JPA 测试。spring-doc.cadn.net.cn

自动配置的数据 JDBC 测试

@DataJdbcTest类似于@JdbcTest但适用于使用 Spring Data JDBC 存储库的测试。 默认情况下,它配置一个内存中嵌入式数据库,一个JdbcTemplate和 Spring Data JDBC 存储库。 只AbstractJdbcConfiguration@DataJdbcTest使用注释,常规@Component@ConfigurationProperties不扫描豆子。@EnableConfigurationProperties可用于包含@ConfigurationProperties豆。spring-doc.cadn.net.cn

启用的自动配置列表@DataJdbcTest可以在附录中找到

默认情况下,数据 JDBC 测试是事务性的,并在每次测试结束时回滚。 有关更多详细信息,请参阅 Spring Framework 参考文档中的相关部分。 如果这不是您想要的,您可以禁用测试或整个测试类的事务管理,如 JDBC 示例所示spring-doc.cadn.net.cn

如果您希望测试针对真实数据库运行,则可以使用@AutoConfigureTestDatabase注释的方式与@DataJpaTest. (请参阅自动配置的数据 JPA 测试。spring-doc.cadn.net.cn

自动配置的数据 R2DBC 测试

@DataR2dbcTest类似于@DataJdbcTest但适用于使用 Spring Data R2DBC 存储库的测试。 默认情况下,它配置一个内存中嵌入式数据库,一个R2dbcEntityTemplate和 Spring Data R2DBC 存储库。 定期@Component@ConfigurationProperties@DataR2dbcTest注释。@EnableConfigurationProperties可用于包含@ConfigurationProperties豆。spring-doc.cadn.net.cn

启用的自动配置列表@DataR2dbcTest可以在附录中找到

默认情况下,数据 R2DBC 测试不是事务性的。spring-doc.cadn.net.cn

如果您希望测试针对真实数据库运行,则可以使用@AutoConfigureTestDatabase注释的方式与@DataJpaTest. (请参阅自动配置的数据 JPA 测试。spring-doc.cadn.net.cn

自动配置的 jOOQ 测试

您可以使用@JooqTest以类似于@JdbcTest但用于与 jOOQ 相关的测试。 由于 jOOQ 严重依赖与数据库模式相对应的基于 Java 的模式,因此现有的DataSource被使用。 如果要用内存数据库替换它,可以使用@AutoConfigureTestDatabase以覆盖这些设置。 (有关将 jOOQ 与 Spring Boot 一起使用的更多信息,请参阅使用 jOOQ。 定期@Component@ConfigurationProperties@JooqTest注释。@EnableConfigurationProperties可用于包含@ConfigurationProperties豆。spring-doc.cadn.net.cn

启用的自动配置列表@JooqTest可以在附录中找到

@JooqTest配置一个DSLContext. 以下示例显示了@JooqTest使用中的注释:spring-doc.cadn.net.cn

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 示例所示spring-doc.cadn.net.cn

自动配置的数据 MongoDB 测试

您可以使用@DataMongoTest测试 MongoDB 应用程序。 默认情况下,它配置了一个MongoTemplate,扫描@Document类,并配置 Spring Data MongoDB 存储库。 定期@Component@ConfigurationProperties@DataMongoTest注释。@EnableConfigurationProperties可用于包含@ConfigurationProperties豆。 (有关将 MongoDB 与 Spring Boot 一起使用的更多信息,请参阅 MongoDBspring-doc.cadn.net.cn

启用的自动配置设置列表@DataMongoTest可以在附录中找到

以下类显示了@DataMongoTest使用中的注释:spring-doc.cadn.net.cn

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) {

	// ...

}

自动配置数据 Neo4j 测试

您可以使用@DataNeo4jTest测试 Neo4j 应用程序。 默认情况下,它会扫描@Node类,并配置 Spring Data Neo4j 存储库。 定期@Component@ConfigurationProperties@DataNeo4jTest注释。@EnableConfigurationProperties可用于包含@ConfigurationProperties豆。 (有关将 Neo4J 与 Spring Boot 一起使用的更多信息,请参阅 Neo4jspring-doc.cadn.net.cn

启用的自动配置设置列表@DataNeo4jTest可以在附录中找到

以下示例显示了在 Spring Boot 中使用 Neo4J 测试的典型设置:spring-doc.cadn.net.cn

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) {

	// ...

}

默认情况下,Data Neo4j 测试是事务性的,并在每次测试结束时回滚。 有关更多详细信息,请参阅 Spring Framework 参考文档中的相关部分。 如果这不是您想要的,您可以禁用测试或整个类的事务管理,如下所示:spring-doc.cadn.net.cn

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
响应式访问不支持事务测试。 如果使用此样式,则必须配置@DataNeo4jTest如上所述的测试。

自动配置的数据 Redis 测试

您可以使用@DataRedisTest测试 Redis 应用程序。 默认情况下,它会扫描@RedisHash类并配置 Spring Data Redis 存储库。 定期@Component@ConfigurationProperties@DataRedisTest注释。@EnableConfigurationProperties可用于包含@ConfigurationProperties豆。 (有关将 Redis 与 Spring Boot 一起使用的更多信息,请参阅 Redisspring-doc.cadn.net.cn

启用的自动配置设置列表@DataRedisTest可以在附录中找到

以下示例显示了@DataRedisTest使用中的注释:spring-doc.cadn.net.cn

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) {

	// ...

}

自动配置的数据 LDAP 测试

您可以使用@DataLdapTest以测试 LDAP 应用程序。 默认情况下,它配置内存中嵌入式 LDAP(如果可用),配置LdapTemplate,扫描@Entry类,并配置 Spring Data LDAP 存储库。 定期@Component@ConfigurationProperties@DataLdapTest注释。@EnableConfigurationProperties可用于包含@ConfigurationProperties豆。 (有关将 LDAP 与 Spring Boot 一起使用的更多信息,请参阅 LDAP。spring-doc.cadn.net.cn

启用的自动配置设置列表@DataLdapTest可以在附录中找到

以下示例显示了@DataLdapTest使用中的注释:spring-doc.cadn.net.cn

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 自动配置,如以下示例所示:spring-doc.cadn.net.cn

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 支持,配置一个RestTemplateBuilderRestClient.Builder,并添加了对MockRestServiceServer. 定期@Component@ConfigurationProperties@RestClientTest注释。@EnableConfigurationProperties可用于包含@ConfigurationProperties豆。spring-doc.cadn.net.cn

启用的自动配置设置列表@RestClientTest可以在附录中找到

要测试的特定 bean 应使用valuecomponents属性@RestClientTest.spring-doc.cadn.net.cn

使用RestTemplateBuilder在被测豆中和RestTemplateBuilder.rootUri(String rootUri)在构建RestTemplate,则应从MockRestServiceServer期望值,如以下示例所示:spring-doc.cadn.net.cn

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")
	}

}

使用RestClient.Builder在被测的 bean 中,或者当使用RestTemplateBuilder无需调用rootUri(String rootURI),则必须在MockRestServiceServer期望值,如以下示例所示:spring-doc.cadn.net.cn

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注释以在测试中使用 Mock MVC、REST Assured 或 WebTestClient 的 Spring REST Docs。 它消除了对 Spring REST Docs 中 JUnit 扩展的需求。spring-doc.cadn.net.cn

@AutoConfigureRestDocs可用于覆盖默认输出目录 (target/generated-snippets如果您使用的是 Maven 或build/generated-snippets如果您使用的是 Gradle)。 它还可用于配置任何记录的 URI 中显示的主机、方案和端口。spring-doc.cadn.net.cn

使用模拟 MVC 自动配置的 Spring REST Docs 测试

@AutoConfigureRestDocs自定义MockMvcbean 在测试基于 servlet 的 Web 应用程序时使用 Spring REST Docs。 您可以使用以下命令来注入它@Autowired并在测试中使用它,就像在使用 Mock MVC 和 Spring REST Docs 时一样,如以下示例所示:spring-doc.cadn.net.cn

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也可用,如以下示例所示:spring-doc.cadn.net.cn

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实例在幕后,因此它的任何配置都适用于两者。spring-doc.cadn.net.cn

如果您需要对 Spring REST Docs 配置进行比@AutoConfigureRestDocs,您可以使用RestDocsMockMvcConfigurationCustomizerbean,如以下示例所示:spring-doc.cadn.net.cn

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())
	}

}

如果您想利用 Spring REST Docs 对参数化输出目录的支持,您可以创建一个RestDocumentationResultHandler豆。 自动配置调用alwaysDo使用此结果处理程序,从而导致每个MockMvc调用自动生成默认代码片段。 以下示例显示了RestDocumentationResultHandler被定义:spring-doc.cadn.net.cn

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}")
	}

}

使用 WebTestClient 自动配置 Spring REST Docs 测试

@AutoConfigureRestDocs也可以与WebTestClient在测试响应式 Web 应用程序时。 您可以使用以下命令来注入它@Autowired并在测试中使用它,就像您通常使用@WebFluxTest和 Spring REST Docs,如以下示例所示:spring-doc.cadn.net.cn

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"))
	}

}

如果您需要对 Spring REST Docs 配置进行比@AutoConfigureRestDocs,您可以使用RestDocsWebTestClientConfigurationCustomizerbean,如以下示例所示:spring-doc.cadn.net.cn

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")
	}

}

如果您想利用 Spring REST Docs 对参数化输出目录的支持,您可以使用WebTestClientBuilderCustomizer为每个实体交换结果配置使用者。 以下示例显示了这样的WebTestClientBuilderCustomizer被定义:spring-doc.cadn.net.cn

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}")
			)
		}
	}

}

使用 REST Assured 自动配置的 Spring REST Docs 测试

@AutoConfigureRestDocs使RequestSpecificationbean,预配置为使用 Spring REST Docs,可用于您的测试。您可以使用@Autowired并在测试中使用它,就像使用 REST Assured 和 Spring REST Docs 时一样,如以下示例所示:spring-doc.cadn.net.cn

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))
	}

}

如果您需要对 Spring REST Docs 配置进行比@AutoConfigureRestDocs一个RestDocsRestAssuredConfigurationCustomizer可以使用 bean,如以下示例所示:spring-doc.cadn.net.cn

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 服务测试

自动配置的 Spring Web Services 客户端测试

您可以使用@WebServiceClientTest测试使用 Spring Web Services 项目调用 Web 服务的应用程序。默认情况下,它配置了一个MockWebServiceServerbean 并自动自定义您的WebServiceTemplateBuilder. (有关将 Web 服务与 Spring Boot 一起使用的更多信息,请参阅 Web 服务spring-doc.cadn.net.cn

启用的自动配置设置列表@WebServiceClientTest可以在附录中找到

以下示例显示了@WebServiceClientTest使用中的注释:spring-doc.cadn.net.cn

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可用于调用 Web 服务端点的 bean。(有关将 Web 服务与 Spring Boot 一起使用的更多信息,请参阅 Web 服务spring-doc.cadn.net.cn

启用的自动配置设置列表@WebServiceServerTest可以在附录中找到

以下示例显示了@WebServiceServerTest使用中的注释:spring-doc.cadn.net.cn

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到测试,如以下示例所示:spring-doc.cadn.net.cn

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如以下示例所示:spring-doc.cadn.net.cn

META-INF/spring/org.springframework.boot.test.autoconfigure.jdbc.JdbcTest.imports
com.example.IntegrationAutoConfiguration

在此示例中,com.example.IntegrationAutoConfiguration在每个标注为@JdbcTest.spring-doc.cadn.net.cn

您可以在此文件中使用注释。#
切片或@AutoConfigure…​注释可以以这种方式自定义,只要它使用@ImportAutoConfiguration.

用户配置和切片

如果您以合理的方式构建代码,则@SpringBootApplicationclass 默认用作测试的配置。spring-doc.cadn.net.cn

然后,重要的是不要在应用程序的主类中乱扔特定于其特定功能区域的配置设置。spring-doc.cadn.net.cn

假设您使用的是 Spring Data MongoDB,您依赖于它的自动配置,并且您已经启用了审计。 您可以定义您的@SpringBootApplication如下:spring-doc.cadn.net.cn

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类,如以下示例所示:spring-doc.cadn.net.cn

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 {

	// ...

}
根据应用程序的复杂性,您可能有一个@Configurationclass 或每个域区域一个类。 后一种方法允许您在其中一个测试中启用它,如有必要,使用@Import注解。 请参阅此作方法部分,了解有关何时可能想要启用特定@Configuration用于切片测试的类。

测试切片排除@Configuration类。 例如,对于@WebMvcTest,则以下配置将不包括给定的WebMvcConfigurerbean 在测试切片加载的应用程序上下文中:spring-doc.cadn.net.cn

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由测试切片加载。spring-doc.cadn.net.cn

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 {

	// ...

}

另一个混淆的来源是类路径扫描。 假设在以合理的方式构建代码时,需要扫描一个额外的包。 应用程序可能类似于以下代码:spring-doc.cadn.net.cn

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似乎突然扫描了应用程序的组件和用户配置。 同样,将自定义指令移动到单独的类是解决此问题的好方法。spring-doc.cadn.net.cn

如果这不适合您,您可以创建一个@SpringBootConfiguration在测试层次结构中的某个位置,以便使用它。 或者,您可以为测试指定源,这会禁用查找默认源的行为。

使用 Spock 测试 Spring Boot 应用程序

Spock 2.2 或更高版本可用于测试 Spring Boot 应用程序。 为此,请添加对-groovy-4.0斯波克的版本spock-spring模块添加到应用程序的构建中。spock-spring将 Spring 的测试框架集成到 Spock 中。 有关更多详细信息,请参阅 Spock 的 Spring 模块的文档spring-doc.cadn.net.cn