此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Framework 6.2.10spring-doc.cadn.net.cn

执行请求

本节介绍如何使用MockMvcTester执行请求及其集成 使用 AssertJ 来验证响应。spring-doc.cadn.net.cn

MockMvcTester提供了一个流畅的 API 来编写重用相同MockHttpServletRequestBuilder作为 Hamcrest 支持,除了没有必要 导入静态方法。返回的构建器是 AssertJ 感知的,因此 用常规包裹它assertThat()factory 方法触发交换和 提供对专用 Assert 对象的访问MvcTestResult.spring-doc.cadn.net.cn

下面是一个简单的示例,它执行POST/hotels/42并配置 请求指定Accept页眉:spring-doc.cadn.net.cn

assertThat(mockMvc.post().uri("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON))
		. // ...
assertThat(mockMvc.post().uri("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON))
	. // ...

AssertJ 通常由多个assertThat()语句来验证不同的 部分交易所。与其像上面的情况那样有一个单一的陈述,不如说 可以使用.exchange()返回MvcTestResult可以用于多个assertThat语句:spring-doc.cadn.net.cn

MvcTestResult result = mockMvc.post().uri("/hotels/{id}", 42)
		.accept(MediaType.APPLICATION_JSON).exchange();
assertThat(result). // ...
val result = mockMvc.post().uri("/hotels/{id}", 42)
	.accept(MediaType.APPLICATION_JSON).exchange()
assertThat(result)
	. // ...

可以在 URI 模板样式中指定查询参数,如以下示例所示:spring-doc.cadn.net.cn

assertThat(mockMvc.get().uri("/hotels?thing={thing}", "somewhere"))
		. // ...
assertThat(mockMvc.get().uri("/hotels?thing={thing}", "somewhere"))
	. // ...

您还可以添加表示查询或表单的 Servlet 请求参数 参数,如以下示例所示:spring-doc.cadn.net.cn

assertThat(mockMvc.get().uri("/hotels").param("thing", "somewhere"))
		. // ...
assertThat(mockMvc.get().uri("/hotels").param("thing", "somewhere"))
	. // ...

如果应用程序代码依赖于 Servlet 请求参数并且不检查查询 字符串显式(最常见的情况),使用哪个选项并不重要。 但是请记住,URI 模板提供的查询参数是解码的 而请求参数通过param(…​)方法预计已经 被解码。spring-doc.cadn.net.cn

异步

如果请求的处理是异步完成的,exchange()等待 请求的完成,以便要断言的结果实际上是不可变的。 默认超时为 10 秒,但可以按请求控制 basis ,如以下示例所示:spring-doc.cadn.net.cn

assertThat(mockMvc.get().uri("/compute").exchange(Duration.ofSeconds(5)))
		. // ...
assertThat(mockMvc.get().uri("/compute").exchange(Duration.ofSeconds(5)))
	. // ...

如果您希望获得原始结果并管理异步的生命周期 请求自己,使用asyncExchange而不是exchange.spring-doc.cadn.net.cn

多部分

您可以执行内部使用MockMultipartHttpServletRequest这样就不会对多部分进行实际解析 请求。相反,您必须将其设置为类似于以下示例:spring-doc.cadn.net.cn

assertThat(mockMvc.post().uri("/upload").multipart()
		.file("file1.txt", "Hello".getBytes(StandardCharsets.UTF_8))
		.file("file2.txt", "World".getBytes(StandardCharsets.UTF_8)))
	. // ...
assertThat(mockMvc.post().uri("/upload").multipart()
		.file("file1.txt", "Hello".toByteArray(StandardCharsets.UTF_8))
		.file("file2.txt", "World".toByteArray(StandardCharsets.UTF_8)))
	. // ...

使用 Servlet 和上下文路径

在大多数情况下,最好将上下文路径和 Servlet 路径留在 请求 URI。如果必须使用完整的请求 URI 进行测试,请务必将contextPathservletPath相应地,以便请求映射正常工作,如以下示例所示 显示:spring-doc.cadn.net.cn

assertThat(mockMvc.get().uri("/app/main/hotels/{id}", 42)
		.contextPath("/app").servletPath("/main"))
		. // ...
assertThat(mockMvc.get().uri("/app/main/hotels/{id}", 42)
		.contextPath("/app").servletPath("/main"))
	. // ...

在前面的示例中,设置contextPathservletPath每个执行的请求。相反,您可以设置默认请求 属性,如以下示例所示:spring-doc.cadn.net.cn

MockMvcTester mockMvc = MockMvcTester.of(List.of(new HotelController()),
		builder -> builder.defaultRequest(get("/")
				.contextPath("/app").servletPath("/main")
				.accept(MediaType.APPLICATION_JSON)).build());
val mockMvc =
	MockMvcTester.of(listOf(HotelController())) { builder: StandaloneMockMvcBuilder ->
		builder.defaultRequest<StandaloneMockMvcBuilder>(
			MockMvcRequestBuilders.get("/")
				.contextPath("/app").servletPath("/main")
				.accept(MediaType.APPLICATION_JSON)
		).build()
	}

上述属性会影响通过mockMvc实例。 如果在给定请求上也指定了相同的属性,则它将覆盖默认值 价值。这就是为什么默认请求中的 HTTP 方法和 URI 无关紧要,因为 必须在每个请求中指定它们。spring-doc.cadn.net.cn