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

MockMvc与HtmlUnit

本节描述了如何集成 MockMvc 和 HtmlUnit。如果您想使用原始的 HtmlUnit 库,请使用此选项。spring-doc.cadn.net.cn

MockMvc 和 HtmlUnit 配置

首先,确保您已经包含了一个对net.sourceforge.htmlunit:htmlunit的测试依赖。为了使用HtmlUnit与Apache HttpComponents 4.5+一起,您需要使用HtmlUnit 2.18或更高版本。spring-doc.cadn.net.cn

我们可以轻松地创建一个HtmlUnit WebClient,它通过使用MockMvcWebClientBuilder与MockMvc集成,如下所示:spring-doc.cadn.net.cn

WebClient webClient;

@BeforeEach
void setup(WebApplicationContext context) {
	webClient = MockMvcWebClientBuilder
			.webAppContextSetup(context)
			.build();
}
lateinit var webClient: WebClient

@BeforeEach
fun setup(context: WebApplicationContext) {
	webClient = MockMvcWebClientBuilder
			.webAppContextSetup(context)
			.build()
}
这是一个使用MockMvcWebClientBuilder的简单示例。有关高级用法, 请参见高级MockMvcWebClientBuilder

这确保了任何引用localhost作为服务器的URL都会被定向到我们的MockMvc实例,而无需实际的HTTP连接。任何其他URL都通过网络连接正常请求。这使我们能够轻松测试CDN的使用。spring-doc.cadn.net.cn

MockMvc 和 HtmlUnit 的使用

现在我们可以像平常一样使用HtmlUnit,而无需将我们的应用程序部署到Servlet容器中。例如,我们可以请求视图以创建一条消息,如下所示:spring-doc.cadn.net.cn

HtmlPage createMsgFormPage = webClient.getPage("http://localhost/messages/form");
val createMsgFormPage = webClient.getPage("http://localhost/messages/form")
默认的上下文路径是""。或者,我们可以指定上下文路径,如高级MockMvcWebClientBuilder中所述。

一旦我们有了HtmlPage的引用,我们就可以填写表单并提交它来创建消息,如下例所示:spring-doc.cadn.net.cn

HtmlForm form = createMsgFormPage.getHtmlElementById("messageForm");
HtmlTextInput summaryInput = createMsgFormPage.getHtmlElementById("summary");
summaryInput.setValueAttribute("Spring Rocks");
HtmlTextArea textInput = createMsgFormPage.getHtmlElementById("text");
textInput.setText("In case you didn't know, Spring Rocks!");
HtmlSubmitInput submit = form.getOneHtmlElementByAttribute("input", "type", "submit");
HtmlPage newMessagePage = submit.click();
val form = createMsgFormPage.getHtmlElementById("messageForm")
val summaryInput = createMsgFormPage.getHtmlElementById("summary")
summaryInput.setValueAttribute("Spring Rocks")
val textInput = createMsgFormPage.getHtmlElementById("text")
textInput.setText("In case you didn't know, Spring Rocks!")
val submit = form.getOneHtmlElementByAttribute("input", "type", "submit")
val newMessagePage = submit.click()

最后,我们可以验证新消息是否成功创建。以下断言使用了AssertJ库:spring-doc.cadn.net.cn

assertThat(newMessagePage.getUrl().toString()).endsWith("/messages/123");
String id = newMessagePage.getHtmlElementById("id").getTextContent();
assertThat(id).isEqualTo("123");
String summary = newMessagePage.getHtmlElementById("summary").getTextContent();
assertThat(summary).isEqualTo("Spring Rocks");
String text = newMessagePage.getHtmlElementById("text").getTextContent();
assertThat(text).isEqualTo("In case you didn't know, Spring Rocks!");
assertThat(newMessagePage.getUrl().toString()).endsWith("/messages/123")
val id = newMessagePage.getHtmlElementById("id").getTextContent()
assertThat(id).isEqualTo("123")
val summary = newMessagePage.getHtmlElementById("summary").getTextContent()
assertThat(summary).isEqualTo("Spring Rocks")
val text = newMessagePage.getHtmlElementById("text").getTextContent()
assertThat(text).isEqualTo("In case you didn't know, Spring Rocks!")

上述代码在多个方面改进了我们的 MockMvc测试。 首先,我们不再需要显式验证表单,然后创建一个看起来像表单的请求。相反,我们请求表单,填写它并提交,从而显著减少了开销。spring-doc.cadn.net.cn

另一个重要因素是HtmlUnit使用Mozilla Rhino引擎来评估JavaScript。这意味着我们还可以测试页面中JavaScript的行为。spring-doc.cadn.net.cn

请参阅HtmlUnit文档以获取有关使用HtmlUnit的更多信息。spring-doc.cadn.net.cn

高级 MockMvcWebClientBuilder

在到目前为止的例子中,我们以最简单的方式使用了MockMvcWebClientBuilder,通过基于Spring TestContext Framework为我们加载的WebApplicationContext来构建一个WebClient。以下示例重复了这种方法:spring-doc.cadn.net.cn

WebClient webClient;

@BeforeEach
void setup(WebApplicationContext context) {
	webClient = MockMvcWebClientBuilder
			.webAppContextSetup(context)
			.build();
}
lateinit var webClient: WebClient

@BeforeEach
fun setup(context: WebApplicationContext) {
	webClient = MockMvcWebClientBuilder
			.webAppContextSetup(context)
			.build()
}

我们还可以指定其他配置选项,如下例所示:spring-doc.cadn.net.cn

WebClient webClient;

@BeforeEach
void setup() {
	webClient = MockMvcWebClientBuilder
		// demonstrates applying a MockMvcConfigurer (Spring Security)
		.webAppContextSetup(context, springSecurity())
		// for illustration only - defaults to ""
		.contextPath("")
		// By default MockMvc is used for localhost only;
		// the following will use MockMvc for example.com and example.org as well
		.useMockMvcForHosts("example.com","example.org")
		.build();
}
lateinit var webClient: WebClient

@BeforeEach
fun setup() {
	webClient = MockMvcWebClientBuilder
		// demonstrates applying a MockMvcConfigurer (Spring Security)
		.webAppContextSetup(context, springSecurity())
		// for illustration only - defaults to ""
		.contextPath("")
		// By default MockMvc is used for localhost only;
		// the following will use MockMvc for example.com and example.org as well
		.useMockMvcForHosts("example.com","example.org")
		.build()
}

作为替代方案,我们可以通过单独配置MockMvc实例并将其提供给MockMvcWebClientBuilder来执行完全相同的设置,如下所示:spring-doc.cadn.net.cn

MockMvc mockMvc = MockMvcBuilders
		.webAppContextSetup(context)
		.apply(springSecurity())
		.build();

webClient = MockMvcWebClientBuilder
		.mockMvcSetup(mockMvc)
		// for illustration only - defaults to ""
		.contextPath("")
		// By default MockMvc is used for localhost only;
		// the following will use MockMvc for example.com and example.org as well
		.useMockMvcForHosts("example.com","example.org")
		.build();
// Not possible in Kotlin until https://youtrack.jetbrains.com/issue/KT-22208 is fixed

这是更冗长的,但是,通过使用MockMvc实例构建WebClient,我们掌握了MockMvc的全部功能。spring-doc.cadn.net.cn

有关创建MockMvc实例的更多信息,请参阅 设置选项