对于最新的稳定版本,请使用 Spring Framework 7.0.6!spring-doc.cadn.net.cn

定义预期

您可以通过在执行请求后追加一个或多个andExpect(..)调用来定义预期,如下例所示。一旦某个预期失败,其他预期将不会被断言。spring-doc.cadn.net.cn

// static import of MockMvcRequestBuilders.* and MockMvcResultMatchers.*

mockMvc.perform(get("/accounts/1")).andExpect(status().isOk());
import org.springframework.test.web.servlet.get

mockMvc.get("/accounts/1").andExpect {
	status { isOk() }
}

您可以在执行请求后附加 andExpectAll(..) 来定义多个预期,如下面的示例所示。与 andExpect(..) 相反,andExpectAll(..) 确保所有提供的预期都会被断言,并且所有失败都会被跟踪并报告。spring-doc.cadn.net.cn

// static import of MockMvcRequestBuilders.* and MockMvcResultMatchers.*

mockMvc.perform(get("/accounts/1")).andExpectAll(
	status().isOk(),
	content().contentType("application/json;charset=UTF-8"));
import org.springframework.test.web.servlet.get

mockMvc.get("/accounts/1").andExpectAll {
	status { isOk() }
	content { contentType(APPLICATION_JSON) }
}

MockMvcResultMatchers.* 提供了一些期望,其中一些进一步嵌套了更详细的期望。spring-doc.cadn.net.cn

期望大致可以分为两类。第一类断言验证响应的属性(例如,响应状态、标头和内容)。这些是最重要的需要断言的结果。spring-doc.cadn.net.cn

第二类断言超出了响应的范围。这些断言允许你检查Spring MVC特有的方面,例如处理请求的控制器方法、是否引发了异常并被处理、模型的内容是什么、选择了哪个视图、添加了哪些闪存属性等等。它们还允许你检查Servlet特有的方面,例如请求和会话属性。spring-doc.cadn.net.cn

以下测试断言绑定或验证失败:spring-doc.cadn.net.cn

mockMvc.perform(post("/persons"))
	.andExpect(status().isOk())
	.andExpect(model().attributeHasErrors("person"));
import org.springframework.test.web.servlet.post

mockMvc.post("/persons").andExpect {
	status { isOk() }
	model {
		attributeHasErrors("person")
	}
}

很多时候,当编写测试时,输出执行请求的结果是非常有用的。你可以按照如下方式操作,其中print()是从MockMvcResultHandlers中静态导入的:spring-doc.cadn.net.cn

mockMvc.perform(post("/persons"))
	.andDo(print())
	.andExpect(status().isOk())
	.andExpect(model().attributeHasErrors("person"));
import org.springframework.test.web.servlet.post

mockMvc.post("/persons").andDo {
		print()
	}.andExpect {
		status { isOk() }
		model {
			attributeHasErrors("person")
		}
	}

只要请求处理不会导致未处理的异常,print() 方法会将所有可用的结果数据打印到 System.out。还有一个 log() 方法和两个额外的 print() 方法变体,一个接受 OutputStream,另一个接受 Writer。例如,调用 print(System.err) 会将结果数据打印到 System.err,而调用 print(myWriter) 会将结果数据打印到自定义的写入器。如果你想将结果数据记录而不是打印,可以调用 log() 方法,该方法将结果数据作为单个 DEBUG 消息在 org.springframework.test.web.servlet.result 日志类别下记录结果数据。spring-doc.cadn.net.cn

在某些情况下,你可能需要直接访问结果并验证一些其他方式无法验证的内容。这可以通过在所有其他期望值之后附加 .andReturn() 来实现,如下例所示:spring-doc.cadn.net.cn

MvcResult mvcResult = mockMvc.perform(post("/persons")).andExpect(status().isOk()).andReturn();
// ...
var mvcResult = mockMvc.post("/persons").andExpect { status { isOk() } }.andReturn()
// ...

如果所有测试都重复相同的预期,你可以在构建MockMvc实例时一次性设置共同的预期,如下例所示:spring-doc.cadn.net.cn

standaloneSetup(new SimpleController())
	.alwaysExpect(status().isOk())
	.alwaysExpect(content().contentType("application/json;charset=UTF-8"))
	.build()
// Not possible in Kotlin until https://youtrack.jetbrains.com/issue/KT-22208 is fixed

请注意,常见的预期总是被应用并且不能被覆盖,除非创建一个单独的MockMvc实例。spring-doc.cadn.net.cn

当JSON响应内容包含使用Spring HATEOAS创建的超媒体链接时,你可以通过使用JsonPath表达式来验证生成的链接,如下例所示:spring-doc.cadn.net.cn

mockMvc.perform(get("/people").accept(MediaType.APPLICATION_JSON))
	.andExpect(jsonPath("$.links[?(@.rel == 'self')].href").value("http://localhost:8080/people"));
mockMvc.get("/people") {
	accept(MediaType.APPLICATION_JSON)
}.andExpect {
	jsonPath("$.links[?(@.rel == 'self')].href") {
		value("http://localhost:8080/people")
	}
}

当XML响应内容包含使用Spring HATEOAS创建的超媒体链接时,你可以通过使用XPath表达式来验证生成的链接:spring-doc.cadn.net.cn

Map<String, String> ns = Collections.singletonMap("ns", "http://www.w3.org/2005/Atom");
mockMvc.perform(get("/handle").accept(MediaType.APPLICATION_XML))
	.andExpect(xpath("/person/ns:link[@rel='self']/@href", ns).string("http://localhost:8080/people"));
val ns = mapOf("ns" to "http://www.w3.org/2005/Atom")
mockMvc.get("/handle") {
	accept(MediaType.APPLICATION_XML)
}.andExpect {
	xpath("/person/ns:link[@rel='self']/@href", ns) {
		string("http://localhost:8080/people")
	}
}