MockMvc和HtmlUnit

本节描述了如何集成MockMvc和HtmlUnit。如果您想使用原始的HtmlUnit库,请使用此选项。

MockMvc和HtmlUnit设置

首先,请确保您已经在net.sourceforge.htmlunit:htmlunit上包含了测试依赖项。为了在Apache HttpComponents 4.5+中使用HtmlUnit,您需要使用HtmlUnit 2.18或更高版本。

我们可以通过使用MockMvcWebClientBuilder轻松创建一个与MockMvc集成的HtmlUnit WebClient,如下所示:

  • Java

  • Kotlin

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的使用。

MockMvc和HtmlUnit使用

现在我们可以像平常一样使用HtmlUnit,但无需将应用部署到Servlet容器。例如,我们可以请求视图以创建一条消息,如下所示:

  • Java

  • Kotlin

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

一旦我们获得了HtmlPage的引用,我们就可以填写表单并提交以创建一条消息,如下例所示:

  • Java

  • Kotlin

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库:

  • Java

  • Kotlin

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测试。首先,我们不再需要显式验证我们的表单,然后创建一个类似表单的请求。相反,我们请求表单,填写并提交它,从而显著减少了开销。

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

有关使用HtmlUnit的更多信息,请参阅HtmlUnit文档

高级MockMvcWebClientBuilder

到目前为止,我们已经以最简单的方式使用了MockMvcWebClientBuilder,通过基于Spring TestContext Framework为我们加载的WebApplicationContext构建了一个WebClient。以下示例中重复了这种方法:

  • Java

  • Kotlin

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

我们也可以指定额外的配置选项,如下例所示:

  • Java

  • Kotlin

WebClient webClient;

@BeforeEach
void setup() {
	webClient = MockMvcWebClientBuilder
		// 演示应用MockMvcConfigurer(Spring Security)
		.webAppContextSetup(context, springSecurity())
		// 仅用于说明 - 默认为""
		.contextPath("")
		// 默认情况下,MockMvc仅用于localhost;
		// 以下将在example.com和example.org上也使用MockMvc
		.useMockMvcForHosts("example.com","example.org")
		.build();
}
lateinit var webClient: WebClient

@BeforeEach
fun setup() {
	webClient = MockMvcWebClientBuilder
		// 演示应用MockMvcConfigurer(Spring Security)
		.webAppContextSetup(context, springSecurity())
		// 仅用于说明 - 默认为""
		.contextPath("")
		// 默认情况下,MockMvc仅用于localhost;
		// 以下将在example.com和example.org上也使用MockMvc
		.useMockMvcForHosts("example.com","example.org")
		.build()
}

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

  • Java

  • Kotlin

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

webClient = MockMvcWebClientBuilder
		.mockMvcSetup(mockMvc)
		// 仅用于说明 - 默认为""
		.contextPath("")
		// 默认情况下,MockMvc仅用于localhost;
		// 以下将在example.com和example.org上也使用MockMvc
		.useMockMvcForHosts("example.com","example.org")
		.build();
// 在修复{ kotlin-issues }/KT-22208之前,这是不可能的

这样做更加冗长,但是通过使用MockMvc实例构建WebClient,我们可以充分利用MockMvc的全部功能。

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