此版本仍在开发中,尚未视为稳定版。如需最新稳定版本,请使用 Spring Boot 4.0.4spring-doc.cadn.net.cn

测试 Spring Boot 应用程序

Spring Boot 应用程序是一个 Spring ApplicationContext,因此除了对普通 Spring 上下文通常所做的操作之外,无需进行任何特殊操作即可对其进行测试。spring-doc.cadn.net.cn

默认情况下,只有当您使用 SpringApplication 创建上下文时,Spring Boot 的外部属性、日志记录和其他功能才会被安装到该上下文中。

Spring Boot 提供了一个 @SpringBootTest 注解,当您需要 Spring Boot 功能时,它可以用作标准 spring-test @ContextConfiguration 注解的替代方案。 该注解通过 SpringApplication 创建ApplicationContext 来工作,这些对象用于您的测试中。 除了 @SpringBootTest 之外,还提供了许多其他注解,用于 测试应用程序更具体的切片spring-doc.cadn.net.cn

如果您使用的是 JUnit 4,请别忘了也在您的测试中添加 @RunWith(SpringRunner.class),否则注解将被忽略。 如果您使用的是 JUnit 6,则无需添加等效的 @ExtendWith(SpringExtension.class),因为 @SpringBootTest 和其他 @…​Test 注解已经用它进行了标注。

默认情况下,@SpringBootTest 不会启动服务器。 您可以使用 @SpringBootTestwebEnvironment 属性来进一步细化测试的运行方式: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 测试框架,您可能习惯于使用 @ContextConfiguration(classes=…​) 来指定要加载哪个 Spring @Configuration。 或者,您可能经常在测试中使用嵌套的 @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 的底层组件扫描配置定义了排除过滤器,用于确保切片按预期工作。 如果您在带有 @SpringBootApplication 注解的类上使用了显式的 @ComponentScan 指令,请注意这些过滤器将被禁用。 如果您正在使用切片,则应重新定义它们。spring-doc.cadn.net.cn

如果您想自定义主配置,可以使用嵌套的 @TestConfiguration 类。 与嵌套的 @Configuration 类不同(后者将替代应用程序的主配置),嵌套的 @TestConfiguration 类是作为应用程序主配置的补充而使用的。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

如果您想更改此行为,可以将 @SpringBootTestuseMainMethod 属性更改为 SpringBootTest.UseMainMethod.ALWAYSSpringBootTest.UseMainMethod.WHEN_AVAILABLE。 当设置为 ALWAYS 时,如果找不到任何 main 方法,测试将失败。 当设置为 WHEN_AVAILABLE 时,如果可用,将使用 main 方法,否则将使用标准加载机制。spring-doc.cadn.net.cn

例如,以下测试将调用 MyApplicationmain 方法以创建 ApplicationContext。 如果主方法设置了额外的配置文件,那么当 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 的重写机制,则需要注意这一点。

使用应用程序参数

如果您的应用程序期望 参数,您可以使用 args 属性让 @SpringBootTest 注入它们。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 查询我们的 Web 端点。 以下集成可用: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.resttestclient.autoconfigure.AutoConfigureRestTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import org.springframework.test.web.servlet.client.RestTestClient;
import org.springframework.test.web.servlet.client.RestTestClient.ResponseSpec;
import org.springframework.test.web.servlet.client.assertj.RestTestClientResponse;

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
@AutoConfigureRestTestClient
@AutoConfigureWebTestClient
class MyMockMvcTests {

	@Test
	void testWithMockMvc(@Autowired MockMvc mvc) throws Exception {
		mvc.perform(get("/"))
				.andExpect(status().isOk())
				.andExpect(content().string("Hello World"));
	}

	@Test // If AssertJ is on the classpath, you can use MockMvcTester
	void testWithMockMvcTester(@Autowired MockMvcTester mvc) {
		assertThat(mvc.get().uri("/"))
				.hasStatusOk()
				.hasBodyTextEqualTo("Hello World");
	}

	@Test
	void testWithRestTestClient(@Autowired RestTestClient restClient) {
		restClient
				.get().uri("/")
				.exchange()
				.expectStatus().isOk()
				.expectBody(String.class).isEqualTo("Hello World");
	}

	@Test // If you prefer AssertJ, dedicated assertions are available
	void testWithRestTestClientAssertJ(@Autowired RestTestClient restClient) {
		ResponseSpec spec = restClient.get().uri("/").exchange();
		RestTestClientResponse response = RestTestClientResponse.from(spec);
		assertThat(response).hasStatusOk()
				.bodyText().isEqualTo("Hello World");
	}

	@Test // If Spring WebFlux is on the classpath
	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.resttestclient.autoconfigure.AutoConfigureRestTestClient
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc
import org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.test.web.reactive.server.expectBody
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.assertj.MockMvcTester
import org.springframework.test.web.servlet.client.RestTestClient
import org.springframework.test.web.servlet.client.assertj.RestTestClientResponse
import org.springframework.test.web.servlet.client.expectBody
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status

@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureRestTestClient
@AutoConfigureWebTestClient
class MyMockMvcTests {

	@Test
	fun testWithMockMvc(@Autowired mvc: MockMvc) {
		mvc.perform(get("/"))
			.andExpect(status().isOk())
			.andExpect(content().string("Hello World"))
	}

	@Test // If AssertJ is on the classpath, you can use MockMvcTester
	fun testWithMockMvcTester(@Autowired mvc: MockMvcTester) {
		assertThat(mvc.get().uri("/")).hasStatusOk()
			.hasBodyTextEqualTo("Hello World")
	}

	@Test
	fun testWithRestTestClient(@Autowired webClient: RestTestClient) {
		webClient
			.get().uri("/")
			.exchange()
			.expectStatus().isOk
			.expectBody<String>().isEqualTo("Hello World")
	}

	@Test // If you prefer AssertJ, dedicated assertions are available
	fun testWithRestTestClientAssertJ(@Autowired webClient: RestTestClient) {
		val spec = webClient.get().uri("/").exchange()
		val response = RestTestClientResponse.from(spec)
		assertThat(response).hasStatusOk().bodyText().isEqualTo("Hello World")
	}


	@Test // If Spring WebFlux is on the classpath
	fun testWithWebTestClient(@Autowired webClient: WebTestClient) {
		webClient
			.get().uri("/")
			.exchange()
			.expectStatus().isOk
			.expectBody<String>().isEqualTo("Hello World")
	}

}
如果您只想关注 Web 层而不启动完整的 ApplicationContext,请考虑改用 使用 @WebMvcTest

使用 Spring WebFlux 端点,您可以按照以下示例所示使用 WebTestClientspring-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.webtestclient.autoconfigure.AutoConfigureWebTestClient;
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.context.SpringBootTest
import org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.test.web.reactive.server.expectBody

@SpringBootTest
@AutoConfigureWebTestClient
class MyMockWebTestClientTests {

	@Test
	fun exampleTest(@Autowired webClient: WebTestClient) {
		webClient
			.get().uri("/")
			.exchange()
			.expectStatus().isOk
			.expectBody<String>().isEqualTo("Hello World")
	}

}

在模拟环境中进行测试通常比使用完整的 Servlet 容器运行更快。 然而,由于模拟发生在 Spring MVC 层,依赖于底层 Servlet 容器行为的代码无法直接通过 MockMvc 进行测试。spring-doc.cadn.net.cn

例如,Spring Boot 的错误处理基于 Servlet 容器提供的“错误页面”支持。 这意味着,尽管你可以测试你的 MVC 层是否按预期抛出和处理异常,但无法直接测试某个特定的自定义错误页面是否被渲染。 如果你需要测试这些底层细节,可以按照下一节所述启动一个完全运行的服务器。spring-doc.cadn.net.cn

使用运行中的服务器进行测试

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

@LocalServerPort 注解可用于将 实际使用的端口 注入到您的测试中。spring-doc.cadn.net.cn

需要向已启动的服务器发起 REST 调用的测试可以通过使用 @AutoConfigureRestTestClient 注解测试类,来自动注入一个 RestTestClientspring-doc.cadn.net.cn

配置好的客户端会将相对链接解析为正在运行的服务器地址,并提供专门用于验证响应的 API,如下例所示:spring-doc.cadn.net.cn

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.web.servlet.client.RestTestClient;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureRestTestClient
class MyRandomPortRestTestClientTests {

	@Test
	void exampleTest(@Autowired RestTestClient restClient) {
		restClient
			.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.resttestclient.autoconfigure.AutoConfigureRestTestClient
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
import org.springframework.test.web.servlet.client.RestTestClient
import org.springframework.test.web.servlet.client.expectBody

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureRestTestClient
class MyRandomPortRestTestClientTests {

	@Test
	fun exampleTest(@Autowired webClient: RestTestClient) {
		webClient
			.get().uri("/")
			.exchange()
			.expectStatus().isOk
			.expectBody<String>().isEqualTo("Hello World")
	}

}

如果您更喜欢使用 AssertJ,可以从 RestTestClientResponse 获取专用的断言,如下例所示:spring-doc.cadn.net.cn

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.web.servlet.client.RestTestClient;
import org.springframework.test.web.servlet.client.RestTestClient.ResponseSpec;
import org.springframework.test.web.servlet.client.assertj.RestTestClientResponse;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureRestTestClient
class MyRandomPortRestTestClientAssertJTests {

	@Test
	void exampleTest(@Autowired RestTestClient restClient) {
		ResponseSpec spec = restClient.get().uri("/").exchange();
		RestTestClientResponse response = RestTestClientResponse.from(spec);
		assertThat(response).hasStatusOk().bodyText().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.resttestclient.autoconfigure.AutoConfigureRestTestClient
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
import org.springframework.test.web.servlet.client.RestTestClient
import org.springframework.test.web.servlet.client.assertj.RestTestClientResponse

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureRestTestClient
class MyRandomPortRestTestClientAssertJTests {

	@Test
	fun exampleTest(@Autowired webClient: RestTestClient) {
		val exchange = webClient.get().uri("/").exchange()
		val response = RestTestClientResponse.from(exchange)
		assertThat(response).hasStatusOk()
			.bodyText().isEqualTo("Hello World")
	}

}

如果您的类路径上有 spring-webflux,您还可以通过使用 @AutoConfigureWebTestClient 注解测试类,来自动装配一个 WebTestClientspring-doc.cadn.net.cn

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.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;
import org.springframework.test.web.reactive.server.WebTestClient;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
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.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.test.web.reactive.server.expectBody

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
class MyRandomPortWebTestClientTests {

	@Test
	fun exampleTest(@Autowired webClient: WebTestClient) {
		webClient
			.get().uri("/")
			.exchange()
			.expectStatus().isOk
			.expectBody<String>().isEqualTo("Hello World")
	}

}
WebTestClient 也可以与 模拟环境 一起使用,无需运行服务器,只需使用来自 spring-boot-webflux-test@AutoConfigureWebTestClient 注解您的测试类即可。
对于某些 切片测试,您可能需要使用 @AutoConfigureWebServer 注解来自动配置一个嵌入式 Web 服务器。

spring-boot-resttestclient 模块还提供了一个 TestRestTemplate 设施:spring-doc.cadn.net.cn

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.resttestclient.TestRestTemplate;
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureTestRestTemplate
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.resttestclient.TestRestTemplate
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureTestRestTemplate
class MyRandomPortTestRestTemplateTests {

	@Test
	fun exampleTest(@Autowired restTemplate: TestRestTemplate) {
		val body = restTemplate.getForObject("/", String::class.java)
		assertThat(body).isEqualTo("Hello World")
	}

}

要使用 TestRestTemplate,还需要添加对 spring-boot-restclient 的依赖。 添加此依赖时请务必注意,因为它会为 RestClient.Builder 启用自动配置。 如果你的主代码中使用了 RestClient.Builder,请将 spring-boot-restclient 依赖声明在应用程序的主类路径(main classpath)中,而不仅仅是在测试类路径(test classpath)中。spring-doc.cadn.net.cn

自定义 RestTestClient

要自定义 RestTestClient bean,请配置一个 RestTestClientBuilderCustomizer bean。 任何此类 bean 都会使用用于创建 RestTestClientRestTestClient.Builder 进行调用。spring-doc.cadn.net.cn

自定义 WebTestClient

要自定义 WebTestClient bean,请配置一个 WebTestClientBuilderCustomizer bean。 任何此类 bean 都会使用用于创建 WebTestClientWebTestClient.Builder 进行调用。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")
		// ...
	}

}

使用观测

如果您使用来自 spring-boot-micrometer-tracing-test@AutoConfigureTracing 或来自 spring-boot-micrometer-metrics-test@AutoConfigureMetrics 来注解 切片测试,它将自动配置一个 ObservationRegistryspring-doc.cadn.net.cn

使用指标

无论您的类路径如何,除了基于内存的注册表外,在使用 @SpringBootTest 时,指标注册表都不会自动配置。spring-doc.cadn.net.cn

如果您需要作为集成测试的一部分将指标导出到不同的后端,请使用 @AutoConfigureMetrics 对其进行注解。spring-doc.cadn.net.cn

如果您使用 @AutoConfigureMetrics 注解 切片测试,它将自动配置一个内存中的 MeterRegistry。 切片测试中的数据导出不支持与 @AutoConfigureMetrics 注解一起使用。spring-doc.cadn.net.cn

使用追踪

无论您的类路径如何,当使用 @SpringBootTest 时,报告数据的跟踪组件都不会自动配置。spring-doc.cadn.net.cn

如果您需要在集成测试中使用这些组件,请使用 @AutoConfigureTracing 注解测试类。spring-doc.cadn.net.cn

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

如果您使用 @AutoConfigureTracing 注解切片测试,它将自动配置一个无操作的 Tracer。 使用 @AutoConfigureTracing 注解时,不支持在切片测试中导出数据。spring-doc.cadn.net.cn

模拟和监视 Bean

在运行测试时,有时需要模拟(mock)应用程序上下文中的某些组件。 例如,你可能在某个远程服务之上封装了一个外观(facade),而该远程服务在开发期间不可用。 当你希望模拟在真实环境中难以触发的故障时,模拟(mocking)也非常有用。spring-doc.cadn.net.cn

Spring Framework 包含一个 @MockitoBean 注解,可用于在您的 ApplicationContext 中定义 Mockito 模拟对象。 此外,@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 结合使用时,Spring Boot 的 测试模块 包含许多可用于自动配置此类“切片”的注解。 它们的工作方式类似,都提供一个用于加载 ApplicationContext@…​Test 注解,以及一个或多个可用于自定义自动配置设置的 @AutoConfigure…​ 注解。spring-doc.cadn.net.cn

每个切片将组件扫描限制为相应的组件,并仅加载非常有限的一组自动配置类。 如果你需要排除其中某个自动配置类,大多数 @…​Test 注解都提供了一个 excludeAutoConfiguration 属性。 或者,你也可以使用 @ImportAutoConfiguration#exclude
在一个测试中使用多个 @…​Test 注解来包含多个“切片”是不被支持的。 如果你需要多个“切片”,请选择其中一个 @…​Test 注解,并手动添加其他“切片”对应的 @AutoConfigure…​ 注解。
也可以将 @AutoConfigure…​ 注解与标准的 @SpringBootTest 注解一起使用。 如果您不想对应用程序进行“切片”,但希望使用一些自动配置的测试 Bean,则可以使用这种组合。

自动配置的 JSON 测试

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

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

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

Spring Boot 包含了基于 AssertJ 的辅助工具,它们与 JSONAssert 和 JsonPath 库协同工作,用于验证 JSON 是否符合预期。 JacksonTesterGsonTesterJsonbTesterBasicJsonTester 类可分别用于 Jackson、Gson、Jsonb 和字符串。 在使用 @JsonTest 时,测试类中的任何辅助字段都可以被 @Autowired。 以下示例展示了一个用于 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 辅助类也可以直接在标准单元测试中使用。 为此,如果您不使用 @JsonTest,请在您的 @BeforeEach 方法中调用该辅助类的 initFields 方法。

如果你使用 Spring Boot 基于 AssertJ 的辅助方法来断言某个 JSON 路径下的数值,根据该数值的类型,你可能无法使用 isEqualTo。 此时,你可以使用 AssertJ 的 satisfies 来断言该值满足给定的条件。 例如,以下示例断言实际数值是一个浮点值,其与 0.15 的偏差在 0.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 测试

要测试 Spring MVC 控制器是否按预期工作,请使用来自 spring-boot-webmvc-test 模块的 @WebMvcTest 注解。@WebMvcTest 自动配置 Spring MVC 基础设施,并将扫描的 Bean 限制为 @Controller@ControllerAdvice@JacksonComponent@JsonComponent(已弃用)、ConverterGenericConverterFilterHandlerInterceptorWebMvcConfigurerWebMvcRegistrationsHandlerMethodArgumentResolver。当使用 @WebMvcTest 注解时,普通的 @Component@ConfigurationProperties Bean 不会被扫描。@EnableConfigurationProperties 可用于包含 @ConfigurationProperties Bean。spring-doc.cadn.net.cn

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

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

@WebMvcTest 还会自动配置 MockMvc。 Mock MVC 提供了一种强大的方式,无需启动完整的 HTTP 服务器即可快速测试 MVC 控制器。 如果可用 AssertJ,MockMvcTester 提供的 AssertJ 支持也会被自动配置。 如果您想在测试中使用 RestTestClient,请使用 @AutoConfigureRestTestClient 注解您的测试类。 随后将自动配置一个使用 Mock MVC 基础设施的 RestTestClientspring-doc.cadn.net.cn

您还可以通过使用 @AutoConfigureMockMvc 注解,在非 @WebMvcTest(例如 @SpringBootTest)中自动配置 MockMvcMockMvcTester。 以下示例使用了 MockMvcTester
import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.webmvc.test.autoconfigure.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.webmvc.test.autoconfigure.WebMvcTest
import org.springframework.http.MediaType
import org.springframework.test.context.bean.override.mockito.MockitoBean
import org.springframework.test.web.servlet.assertj.MockMvcTester

@WebMvcTest(UserVehicleController::class)
class MyControllerTests(@Autowired val mvc: MockMvcTester) {

	@MockitoBean
	lateinit var userVehicleService: UserVehicleService

	@Test
	fun testExample() {
		given(userVehicleService.getVehicleDetails("sboot"))
				.willReturn(VehicleDetails("Honda", "Civic"))
		assertThat(mvc.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
				.hasStatusOk().hasBodyTextEqualTo("Honda Civic")
	}

}
如果您需要配置自动装配的元素(例如,何时应用 Servlet 过滤器),您可以在 @AutoConfigureMockMvc 注解中使用属性。

如果您使用 HtmlUnit 和 Selenium,自动配置还会提供一个 HtmlUnit WebClient Bean 和/或一个 Selenium WebDriver Bean。 以下示例使用了 HtmlUnit: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.webmvc.test.autoconfigure.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.webmvc.test.autoconfigure.WebMvcTest
import org.springframework.test.context.bean.override.mockito.MockitoBean

@WebMvcTest(UserVehicleController::class)
class MyHtmlUnitTests(@Autowired val webClient: WebClient) {

	@MockitoBean
	lateinit var userVehicleService: UserVehicleService

	@Test
	fun testExample() {
		given(userVehicleService.getVehicleDetails("sboot")).willReturn(VehicleDetails("Honda", "Civic"))
		val page = webClient.getPage<HtmlPage>("/sboot/vehicle.html")
		assertThat(page.body.textContent).isEqualTo("Honda Civic")
	}

}
默认情况下,Spring Boot 将 WebDriver Bean 放入一个特殊的“作用域”中,以确保驱动程序在每次测试后退出,并注入一个新的实例。 如果您不希望出现此行为,可以在您的 WebDriver @Bean 定义中添加 @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
Spring Boot 创建的 webDriver 作用域将替换任何同名的用户自定义作用域。 如果您定义了自己的 webDriver 作用域,可能会发现当您使用 @WebMvcTest 时它停止工作。

如果您的类路径上有 Spring Security,@WebMvcTest 还将扫描 WebSecurityConfigurer Bean。 您无需完全禁用此类测试的安全功能,而是可以使用 Spring Security 的测试支持。 有关如何使用 Spring Security 的 MockMvc 支持的更多详细信息,请参阅本“操作指南”部分中的 使用 Spring Security 进行测试spring-doc.cadn.net.cn

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

自动配置的 Spring WebFlux 测试

要测试 Spring WebFlux 控制器是否按预期工作,您可以使用来自 spring-boot-webflux-test 模块的 @WebFluxTest 注解。 @WebFluxTest 会自动配置 Spring WebFlux 基础设施,并将扫描的 Bean 限制为 @Controller@ControllerAdvice@JacksonComponent@JsonComponent(已弃用)、ConverterGenericConverterWebFluxConfigurer。 当使用 @WebFluxTest 注解时,不会扫描常规的 @Component@ConfigurationProperties Bean。 可以使用 @EnableConfigurationProperties 来包含 @ConfigurationProperties Bean。spring-doc.cadn.net.cn

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

通常,@WebFluxTest 仅限于单个控制器,并与 @MockitoBean 注解结合使用,以提供所需协作者的模拟实现。spring-doc.cadn.net.cn

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

您还可以通过使用 @AutoConfigureWebTestClient 注解,在非 @WebFluxTest(例如 @SpringBootTest)中自动配置 WebTestClient

以下示例展示了一个同时使用 @WebFluxTestWebTestClient 的类:spring-doc.cadn.net.cn

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.webflux.test.autoconfigure.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.webflux.test.autoconfigure.WebFluxTest
import org.springframework.http.MediaType
import org.springframework.test.context.bean.override.mockito.MockitoBean
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.test.web.reactive.server.expectBody

@WebFluxTest(UserVehicleController::class)
class MyControllerTests(@Autowired val webClient: WebTestClient) {

	@MockitoBean
	lateinit var userVehicleService: UserVehicleService

	@Test
	fun testExample() {
		given(userVehicleService.getVehicleDetails("sboot"))
			.willReturn(VehicleDetails("Honda", "Civic"))
		webClient.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN).exchange()
			.expectStatus().isOk
			.expectBody<String>().isEqualTo("Honda Civic")
	}

}
此设置仅由 WebFlux 应用程序支持,因为在模拟的 Web 应用程序中使用 WebTestClient 目前仅适用于 WebFlux。
@WebFluxTest 无法检测通过函数式 Web 框架注册的路由。 若要测试上下文中的 RouterFunction Bean,请考虑使用 @Import@SpringBootTest 自行导入您的 RouterFunction
@WebFluxTest 无法检测注册为 @Bean 类型(SecurityWebFilterChain)的自定义安全配置。 若要将其包含在您的测试中,您需要使用 @Import 导入注册该 Bean 的配置,或使用 @SpringBootTest
有时仅编写 Spring WebFlux 测试还不够;Spring Boot 可以帮助你使用真实的服务器运行完整的端到端测试

自动配置的 Spring GraphQL 测试

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

Maven
<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 借助 spring-boot-graphql-test 模块中的 @GraphQlTest 注解,帮助您测试 Spring GraphQL 控制器@GraphQlTest 自动配置 Spring GraphQL 基础设施,不涉及任何传输或服务器。这将扫描的 Bean 限制为 @ControllerRuntimeWiringConfigurerJacksonComponent@JsonComponent(已弃用)、ConverterGenericConverterDataFetcherExceptionResolverInstrumentationGraphQlSourceBuilderCustomizer。当使用 @GraphQlTest 注解时,普通的 @Component@ConfigurationProperties Bean 不会被扫描。@EnableConfigurationProperties 可用于包含 @ConfigurationProperties Bean。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.graphql.test.autoconfigure.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.graphql.test.autoconfigure.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 测试是完整的集成测试,涉及整个应用程序。 可以通过使用来自 spring-boot-graphql-test 模块的 @AutoConfigureHttpGraphQlTester 注解您的测试类来添加 HttpGraphQlTester Bean:spring-doc.cadn.net.cn

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.graphql.test.autoconfigure.tester.AutoConfigureHttpGraphQlTester;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.graphql.test.tester.HttpGraphQlTester;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureHttpGraphQlTester
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.graphql.test.autoconfigure.tester.AutoConfigureHttpGraphQlTester
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
import org.springframework.graphql.test.tester.HttpGraphQlTester
import org.springframework.http.HttpHeaders
import org.springframework.test.web.reactive.server.WebTestClient

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureHttpGraphQlTester
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!")
	}
}

HttpGraphQlTester Bean 使用集成测试的相关传输。 当使用随机端口或指定端口时,测试器会针对实时服务器进行配置。 若要将测试器绑定到 MockMvc,请确保使用 @AutoConfigureMockMvc 注解您的测试类。spring-doc.cadn.net.cn

自动配置的数据 Cassandra 测试

您可以使用 @DataCassandraTest(来自 spring-boot-data-cassandra-test 模块)来测试 Data Cassandra 应用程序。 默认情况下,它会配置一个 CassandraTemplate,扫描 @Table 类,并配置 Spring Data Cassandra 仓库。 当使用 @DataCassandraTest 注解时,常规的 @Component@ConfigurationProperties Bean 不会被扫描。 可以使用 @EnableConfigurationProperties 来包含 @ConfigurationProperties Bean。 (有关在 Spring Boot 中使用 Cassandra 的更多信息,请参阅 Cassandra。)spring-doc.cadn.net.cn

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

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.data.cassandra.test.autoconfigure.DataCassandraTest;

@DataCassandraTest
class MyDataCassandraTests {

	@Autowired
	private SomeRepository repository;

}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.data.cassandra.test.autoconfigure.DataCassandraTest

@DataCassandraTest
class MyDataCassandraTests(@Autowired val repository: SomeRepository)

自动配置的 Data Couchbase 测试

您可以使用 @DataCouchbaseTest(来自 spring-boot-data-couchbase-test 模块)来测试 Data Couchbase 应用程序。 默认情况下,它会配置 CouchbaseTemplateReactiveCouchbaseTemplate,扫描 @Document 类,并配置 Spring Data Couchbase 仓库。 当使用 @DataCouchbaseTest 注解时,不会扫描常规的 @Component@ConfigurationProperties Bean。 可以使用 @EnableConfigurationProperties 来包含 @ConfigurationProperties Bean。 (有关在 Spring Boot 中使用 Couchbase 的更多信息,请参阅本章前面的 Couchbase 部分。)spring-doc.cadn.net.cn

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

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.data.couchbase.test.autoconfigure.DataCouchbaseTest;

@DataCouchbaseTest
class MyDataCouchbaseTests {

	@Autowired
	private SomeRepository repository;

	// ...

}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.data.couchbase.test.autoconfigure.DataCouchbaseTest

@DataCouchbaseTest
class MyDataCouchbaseTests(@Autowired val repository: SomeRepository) {

	// ...

}

自动配置的数据 Elasticsearch 测试

您可以使用 @DataElasticsearchTest(来自 spring-boot-data-elasticsearch-test 模块)来测试 Data Elasticsearch 应用程序。 默认情况下,它会配置一个 ElasticsearchTemplate,扫描 @Document 类,并配置 Spring Data Elasticsearch 仓库。 当使用 @DataElasticsearchTest 注解时,常规的 @Component@ConfigurationProperties Bean 不会被扫描。 可以使用 @EnableConfigurationProperties 来包含 @ConfigurationProperties Bean。 (有关在 Spring Boot 中使用 Elasticsearch 的更多信息,请参阅本章前面的 Elasticsearch 部分。)spring-doc.cadn.net.cn

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

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.data.elasticsearch.test.autoconfigure.DataElasticsearchTest;

@DataElasticsearchTest
class MyDataElasticsearchTests {

	@Autowired
	private SomeRepository repository;

	// ...

}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.data.elasticsearch.test.autoconfigure.DataElasticsearchTest

@DataElasticsearchTest
class MyDataElasticsearchTests(@Autowired val repository: SomeRepository) {

	// ...

}

自动配置的数据 JPA 测试

您可以使用来自 spring-boot-data-jpa-test 模块的 @DataJpaTest 注解来测试 Data JPA 应用程序。 默认情况下,它会扫描 @Entity 类并配置 Spring Data JPA 仓库。 如果类路径上存在嵌入式数据库,它也会进行相应配置。 通过将 spring.jpa.show-sql 属性设置为 true,默认情况下会记录 SQL 查询。 可以使用该注解的 showSql 属性来禁用此功能。spring-doc.cadn.net.cn

当使用 @DataJpaTest 注解时,普通的 @Component@ConfigurationProperties Bean 不会被扫描。 可以使用 @EnableConfigurationProperties 来包含 @ConfigurationProperties Bean。spring-doc.cadn.net.cn

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

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

import org.springframework.boot.data.jpa.test.autoconfigure.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.data.jpa.test.autoconfigure.DataJpaTest
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional

@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyNonTransactionalTests {

	// ...

}

Data JPA 测试还可以注入一个 TestEntityManager Bean,它提供了一种替代标准 JPA EntityManager 的方案,专为测试而设计。spring-doc.cadn.net.cn

TestEntityManager 也可以通过添加 @AutoConfigureTestEntityManager 自动配置到您的任何基于 Spring 的测试类中。 执行此操作时,请确保您的测试在事务中运行,例如通过在测试类或方法上添加 @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.data.jpa.test.autoconfigure.DataJpaTest;
import org.springframework.boot.jpa.test.autoconfigure.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.data.jpa.test.autoconfigure.DataJpaTest
import org.springframework.boot.jpa.test.autoconfigure.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.data.jpa.test.autoconfigure.DataJpaTest;
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase.Replace;

@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
class MyRepositoryTests {

	// ...

}
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class MyRepositoryTests {

	// ...

}

自动配置的 JDBC 测试

@JdbcTest 来自 spring-boot-jdbc-test 模块,类似于 @DataJdbcTest,但适用于仅需 DataSource 且不使用 Spring Data JDBC 的测试。 默认情况下,它会配置一个内存嵌入式数据库和一个 JdbcTemplate。 当使用 @JdbcTest 注解时,不会扫描常规的 @Component@ConfigurationProperties Bean。 可以使用 @EnableConfigurationProperties 来包含 @ConfigurationProperties Bean。spring-doc.cadn.net.cn

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

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

import org.springframework.boot.jdbc.test.autoconfigure.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.jdbc.test.autoconfigure.JdbcTest
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional

@JdbcTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyTransactionalTests

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

自动配置的数据 JDBC 测试

@DataJdbcTest 来自 spring-boot-data-jdbc-test 模块,类似于 @JdbcTest,但适用于使用 Spring Data JDBC 存储库的测试。 默认情况下,它会配置一个内存嵌入式数据库、一个 JdbcTemplate 以及 Spring Data JDBC 存储库。 仅当使用 @DataJdbcTest 注解时,才会扫描 AbstractJdbcConfiguration 的子类,常规的 @Component@ConfigurationProperties Bean 不会被扫描。 可以使用 @EnableConfigurationProperties 来包含 @ConfigurationProperties Bean。spring-doc.cadn.net.cn

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

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

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

自动配置的数据 R2DBC 测试

@DataR2dbcTest 来自 spring-boot-data-r2dbc-test 模块,类似于 @DataJdbcTest,但适用于使用 Spring Data R2DBC 存储库的测试。 默认情况下,它会配置一个内存嵌入式数据库、一个 R2dbcEntityTemplate 以及 Spring Data R2DBC 存储库。 当使用 @DataR2dbcTest 注解时,不会扫描常规的 @Component@ConfigurationProperties Bean。 可以使用 @EnableConfigurationProperties 来包含 @ConfigurationProperties Bean。spring-doc.cadn.net.cn

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

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

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

自动配置的 jOOQ 测试

您可以使用来自 spring-boot-jooq-test@JooqTest,其用法类似于 @JdbcTest,但专用于 jOOQ 相关的测试。 由于 jOOQ 严重依赖于与数据库架构相对应的基于 Java 的架构,因此会使用现有的 DataSource。 如果您希望将其替换为内存数据库,可以使用 @AutoConfigureTestDatabase 来覆盖这些设置。 (有关在 Spring Boot 中使用 jOOQ 的更多信息,请参阅 使用 jOOQ。) 当使用 @JooqTest 注解时,常规的 @Component@ConfigurationProperties Bean 不会被扫描。 可以使用 @EnableConfigurationProperties 来包含 @ConfigurationProperties Bean。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.jooq.test.autoconfigure.JooqTest;

@JooqTest
class MyJooqTests {

	@Autowired
	private DSLContext dslContext;

	// ...

}
import org.jooq.DSLContext
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.jooq.test.autoconfigure.JooqTest

@JooqTest
class MyJooqTests(@Autowired val dslContext: DSLContext) {

	// ...

}

JOOQ 测试默认是事务性的,并且在每个测试结束时自动回滚。 如果你不希望如此,可以按照JDBC 示例中所示,为单个测试或整个测试类禁用事务管理。spring-doc.cadn.net.cn

自动配置的 Data MongoDB 测试

您可以使用 @DataMongoTest(来自 spring-boot-data-mongodb-test 模块)来测试 MongoDB 应用程序。 默认情况下,它会配置一个 MongoTemplate,扫描 @Document 类,并配置 Spring Data MongoDB 仓库。 当使用 @DataMongoTest 注解时,不会扫描常规的 @Component@ConfigurationProperties Bean。 可以使用 @EnableConfigurationProperties 来包含 @ConfigurationProperties Bean。 (有关在 Spring Boot 中使用 MongoDB 的更多信息,请参阅 MongoDB。)spring-doc.cadn.net.cn

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

以下类展示了 @DataMongoTest 注解的使用:spring-doc.cadn.net.cn

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.data.mongodb.test.autoconfigure.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.data.mongodb.test.autoconfigure.DataMongoTest
import org.springframework.data.mongodb.core.MongoTemplate

@DataMongoTest
class MyDataMongoDbTests(@Autowired val mongoTemplate: MongoTemplate) {

	// ...

}

自动配置的 Data Neo4j 测试

您可以使用 @DataNeo4jTest(来自 spring-boot-data-neo4j-test 模块)来测试 Neo4j 应用程序。 默认情况下,它会扫描 @Node 类,并配置 Spring Data Neo4j 仓库。 当使用 @DataNeo4jTest 注解时,常规的 @Component@ConfigurationProperties Bean 不会被扫描。 可以使用 @EnableConfigurationProperties 来包含 @ConfigurationProperties Bean。 (有关在 Spring Boot 中使用 Neo4j 的更多信息,请参阅 Neo4j。)spring-doc.cadn.net.cn

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

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.data.neo4j.test.autoconfigure.DataNeo4jTest;

@DataNeo4jTest
class MyDataNeo4jTests {

	@Autowired
	private SomeRepository repository;

	// ...

}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.data.neo4j.test.autoconfigure.DataNeo4jTest

@DataNeo4jTest
class MyDataNeo4jTests(@Autowired val repository: SomeRepository) {

	// ...

}

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

import org.springframework.boot.data.neo4j.test.autoconfigure.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.data.neo4j.test.autoconfigure.DataNeo4jTest
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional

@DataNeo4jTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyDataNeo4jTests
事务性测试不支持响应式访问。 如果您使用这种风格,必须按照上述说明配置 @DataNeo4jTest 测试。

自动配置的数据 Redis 测试

您可以使用 @DataRedisTest(来自 spring-boot-data-redis-test 模块)来测试 Data Redis 应用程序。 默认情况下,它会扫描 @RedisHash 类并配置 Spring Data Redis 仓库。 当使用 @DataRedisTest 注解时,常规的 @Component@ConfigurationProperties Bean 不会被扫描。 可以使用 @EnableConfigurationProperties 来包含 @ConfigurationProperties Bean。 (有关在 Spring Boot 中使用 Redis 的更多信息,请参阅 Redis。)spring-doc.cadn.net.cn

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

以下示例展示了 @DataRedisTest 注解的使用:spring-doc.cadn.net.cn

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.data.redis.test.autoconfigure.DataRedisTest;

@DataRedisTest
class MyDataRedisTests {

	@Autowired
	private SomeRepository repository;

	// ...

}
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.data.redis.test.autoconfigure.DataRedisTest

@DataRedisTest
class MyDataRedisTests(@Autowired val repository: SomeRepository) {

	// ...

}

自动配置的数据 LDAP 测试

您可以使用 @DataLdapTest 来测试 Data LDAP 应用程序。 默认情况下,它会配置一个内存中的嵌入式 LDAP(如果可用),配置一个 LdapTemplate,扫描 @Entry 类,并配置 Spring Data LDAP 仓库。 当使用 @DataLdapTest 注解时,不会扫描常规的 @Component@ConfigurationProperties Bean。 可以使用 @EnableConfigurationProperties 来包含 @ConfigurationProperties Bean。 (有关在 Spring Boot 中使用 LDAP 的更多信息,请参阅 LDAP。)spring-doc.cadn.net.cn

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

以下示例展示了 @DataLdapTest 注解的使用:spring-doc.cadn.net.cn

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.data.ldap.test.autoconfigure.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.data.ldap.test.autoconfigure.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.data.ldap.test.autoconfigure.DataLdapTest;
import org.springframework.boot.ldap.autoconfigure.embedded.EmbeddedLdapAutoConfiguration;

@DataLdapTest(excludeAutoConfiguration = EmbeddedLdapAutoConfiguration.class)
class MyDataLdapTests {

	// ...

}
import org.springframework.boot.ldap.autoconfigure.embedded.EmbeddedLdapAutoConfiguration
import org.springframework.boot.data.ldap.test.autoconfigure.DataLdapTest

@DataLdapTest(excludeAutoConfiguration = [EmbeddedLdapAutoConfiguration::class])
class MyDataLdapTests {

	// ...

}

自动配置的 REST 客户端

您可以使用来自 spring-boot-restclient-test 模块的 @RestClientTest 注解来测试 REST 客户端。 默认情况下,它会自动配置 Jackson、GSON 和 Jsonb 支持,配置一个 RestTemplateBuilder 和一个 RestClient.Builder,并添加对 MockRestServiceServer 的支持。 当使用 @RestClientTest 注解时,不会扫描常规的 @Component@ConfigurationProperties Bean。 @EnableConfigurationProperties 可用于包含 @ConfigurationProperties Bean。spring-doc.cadn.net.cn

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

您想要测试的具体 Bean 应通过使用 @RestClientTestvaluecomponents 属性来指定。spring-doc.cadn.net.cn

当在被测试的 bean 中使用 RestTemplateBuilder,并且在构建 RestTemplate 时已调用 RestTemplateBuilder.rootUri(String rootUri),则应从 MockRestServiceServer 期望中省略根 URI,如下例所示:spring-doc.cadn.net.cn

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.restclient.test.autoconfigure.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.restclient.test.autoconfigure.RestClientTest
import org.springframework.http.MediaType
import org.springframework.test.web.client.MockRestServiceServer
import org.springframework.test.web.client.match.MockRestRequestMatchers
import org.springframework.test.web.client.response.MockRestResponseCreators

@RestClientTest(RemoteVehicleDetailsService::class)
class MyRestTemplateServiceTests(
	@Autowired val service: RemoteVehicleDetailsService,
	@Autowired val server: MockRestServiceServer) {

	@Test
	fun getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() {
		server.expect(MockRestRequestMatchers.requestTo("/greet/details"))
			.andRespond(MockRestResponseCreators.withSuccess("hello", MediaType.TEXT_PLAIN))
		val greeting = service.callRestService()
		assertThat(greeting).isEqualTo("hello")
	}

}

当在被测试的 bean 中使用 RestClient.Builder,或在使用 RestTemplateBuilder 而未调用 rootUri(String rootURI) 时,必须在 MockRestServiceServer 预期中使用完整 URI,如下例所示:spring-doc.cadn.net.cn

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.restclient.test.autoconfigure.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.restclient.test.autoconfigure.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")
	}

}

自动配置的 Web 客户端

您可以使用来自 spring-boot-webclient-test 模块的 @WebClientTest 注解来测试使用 WebClient 的代码。 默认情况下,它会自动配置 Jackson、GSON 和 Jsonb 支持,并配置一个 WebClient.Builder。 当使用 @WebClientTest 注解时,不会扫描常规的 @Component@ConfigurationProperties Bean。 可以使用 @EnableConfigurationProperties 来包含 @ConfigurationProperties Bean。spring-doc.cadn.net.cn

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

您想要测试的具体 Bean 应通过使用 @WebClientTestvaluecomponents 属性来指定。spring-doc.cadn.net.cn

自动配置的 Spring REST Docs 测试

您可以使用 `spring-boot-restdocs-` 模块中的 @AutoConfigureRestDocs 注解,在您的测试中通过 Mock MVC 或 WebTestClient 来使用 Spring REST Docs。 它消除了对 Spring REST Docs 中 JUnit 扩展的需求。spring-doc.cadn.net.cn

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

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

@AutoConfigureRestDocs 自定义 MockMvc Bean,以便在测试基于 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.restdocs.test.autoconfigure.AutoConfigureRestDocs;
import org.springframework.boot.webmvc.test.autoconfigure.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.restdocs.test.autoconfigure.AutoConfigureRestDocs;
import org.springframework.boot.webmvc.test.autoconfigure.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

如果您需要比 @AutoConfigureRestDocs 的属性所提供的更精细的 Spring REST Docs 配置控制,可以使用 RestDocsMockMvcConfigurationCustomizer Bean,如下例所示:spring-doc.cadn.net.cn

import org.springframework.boot.restdocs.test.autoconfigure.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.restdocs.test.autoconfigure.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 Bean。 自动配置会使用此结果处理器调用 alwaysDo,从而使每次 MockMvc 调用都会自动生成默认代码片段。 以下示例展示了如何定义一个 RestDocumentationResultHandlerspring-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 也可在测试响应式 Web 应用程序时与 WebTestClient 一起使用。 您可以通过使用 @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.restdocs.test.autoconfigure.AutoConfigureRestDocs;
import org.springframework.boot.webflux.test.autoconfigure.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.restdocs.test.autoconfigure.AutoConfigureRestDocs
import org.springframework.boot.webflux.test.autoconfigure.WebFluxTest
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation
import org.springframework.test.web.reactive.server.WebTestClient

@WebFluxTest
@AutoConfigureRestDocs
class MyUsersDocumentationTests(@Autowired val webTestClient: WebTestClient) {

	@Test
	fun listUsers() {
		webTestClient
			.get().uri("/")
			.exchange()
			.expectStatus()
			.isOk
			.expectBody()
			.consumeWith(WebTestClientRestDocumentation.document("list-users"))
	}

}

如果您需要比 @AutoConfigureRestDocs 的属性所提供的更精细的 Spring REST Docs 配置控制,可以使用 RestDocsWebTestClientConfigurationCustomizer Bean,如下例所示:spring-doc.cadn.net.cn

import org.springframework.boot.restdocs.test.autoconfigure.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.restdocs.test.autoconfigure.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 来为每个实体交换结果配置一个消费者。 以下示例展示了如何定义这样一个 WebTestClientBuilderCustomizerspring-doc.cadn.net.cn

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.webtestclient.autoconfigure.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.webtestclient.autoconfigure.WebTestClientBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation
import org.springframework.test.web.reactive.server.WebTestClient

@TestConfiguration(proxyBeanMethods = false)
class MyWebTestClientBuilderCustomizerConfiguration {

	@Bean
	fun restDocumentation(): WebTestClientBuilderCustomizer {
		return WebTestClientBuilderCustomizer { builder: WebTestClient.Builder ->
			builder.entityExchangeResultConsumer(
				WebTestClientRestDocumentation.document("{method-name}")
			)
		}
	}

}

自动配置的 Spring Web Services 测试

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

您可以使用 @WebServiceClientTest(来自 spring-boot-webservices-test 模块)来测试调用 Spring Web Services 项目中 Web 服务的应用程序。 默认情况下,它会配置一个 MockWebServiceServer Bean,并自动自定义您的 WebServiceTemplateBuilder。 (有关在 Spring Boot 中使用 Web 服务的更多信息,请参阅 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.webservices.test.autoconfigure.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.webservices.test.autoconfigure.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-boot-webservices-test 模块)来测试使用 Spring Web Services 项目实现 Web 服务的应用程序。 默认情况下,它会配置一个 MockWebServiceClient Bean,可用于调用您的 Web 服务端点。 (有关在 Spring Boot 中使用 Web 服务的更多信息,请参阅 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.webservices.test.autoconfigure.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.webservices.test.autoconfigure.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.integration.autoconfigure.IntegrationAutoConfiguration;
import org.springframework.boot.jdbc.test.autoconfigure.JdbcTest;

@JdbcTest
@ImportAutoConfiguration(IntegrationAutoConfiguration.class)
class MyJdbcTests {

}
import org.springframework.boot.autoconfigure.ImportAutoConfiguration
import org.springframework.boot.integration.autoconfigure.IntegrationAutoConfiguration
import org.springframework.boot.jdbc.test.autoconfigure.JdbcTest

@JdbcTest
@ImportAutoConfiguration(IntegrationAutoConfiguration::class)
class MyJdbcTests
请确保不要使用普通的 @Import 注解来导入自动配置,因为 Spring Boot 会以特定方式处理它们。

或者,可以通过在 META-INF/spring 目录下创建一个文件来注册额外的自动配置,从而为任何切片注解的使用添加这些配置,如下例所示:spring-doc.cadn.net.cn

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

在此示例中,com.example.IntegrationAutoConfiguration 在每个使用 @JdbcTest 注解的测试中均被启用。spring-doc.cadn.net.cn

你可以在该文件中使用 # 进行注释。
只要使用 @ImportAutoConfiguration 进行元注解,就可以通过这种方式自定义切片或 @AutoConfigure…​ 注解。

用户配置与切片

如果您以合理的方式 组织代码,那么您的 @SpringBootApplication 类将默认被 用作 测试的配置。spring-doc.cadn.net.cn

因此,避免在应用程序的主类中混杂特定于其某项功能领域的配置设置就变得尤为重要。spring-doc.cadn.net.cn

假设您正在使用 Spring Data MongoDB,依赖其自动配置,并且已启用审计功能。 您可以按如下方式定义您的 @SpringBootApplicationspring-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 {

	// ...

}
根据应用程序的复杂程度,您可以为自定义配置使用单个 @Configuration 类,也可以为每个领域区域使用一个类。 后一种方法允许您在必要时通过 @Import 注解在某个测试中启用它。 请参阅 此操作指南部分,了解更多关于何时可能希望为切片测试启用特定 @Configuration 类的详细信息。

测试切片会从扫描中排除 @Configuration 类。 例如,对于 @WebMvcTest,以下配置将不会把指定的 WebMvcConfigurer Bean 包含在由该测试切片加载的应用上下文中: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 {

	// ...

}

另一个容易引起混淆的地方是类路径扫描(classpath scanning)。 假设你已经以一种合理的方式组织了代码,但仍需要扫描一个额外的包。 你的应用程序可能类似于以下代码: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.4 或更高版本来测试 Spring Boot 应用程序。 为此,请在应用程序的构建文件中添加对 Spock 的 -groovy-5.0 模块的 spock-spring 版本的依赖。 spock-spring 将 Spring 的测试框架集成到 Spock 中。 更多详细信息,请参阅Spock Spring 模块的文档spring-doc.cadn.net.cn