MockMvc and HtmlUnit

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

MockMvc and HtmlUnit Setup

首先,确保已包含对 org.htmlunit:htmlunit 的测试依赖。

我们可以使用 MockMvcWebClientBuilder 用 MockMvc 集成的 WebClient 很容易创建 HtmlUnit,如下所示:

  • 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 的简单示例。有关高级用法,请参阅 xref:testing/mockmvc/htmlunit/mah.adoc#spring-mvc-test-server-htmlunit-mah-advanced-builder[Advanced MockMvcWebClientBuilder

这确保了将任何引用 localhost 作为服务器的 URL 定向到我们的 MockMvc 实例,而不需要真正的 HTTP 连接。任何其他 URL 都按正常方式使用网络连接请求。这让我们很容易测试 CDN 的使用。

MockMvc and HtmlUnit Usage

现在,我们可以像往常一样使用 HtmlUnit,但不需要将我们的应用程序部署到 Servlet 容器中。例如,我们可以请求视图来用以下方法创建一个消息:

  • Java

  • Kotlin

HtmlPage createMsgFormPage = webClient.getPage("http://localhost/messages/form");
val createMsgFormPage = webClient.getPage("http://localhost/messages/form")

默认上下文路径为 ""。另外,我们还可以指定上下文路径,如 xref:testing/mockmvc/htmlunit/mah.adoc#spring-mvc-test-server-htmlunit-mah-advanced-builder[Advanced 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 test 。首先,我们不再必须明确验证我们的表单,然后创建一个与该表单相似的请求。相反,我们请求表单、填写它并提交它,从而显著减少了开销。

另一个重要因素是 HtmlUnit uses the Mozilla Rhino engine用于评估 JavaScript。这意味着我们还可以在页面中测试 JavaScript 的行为。

请参阅 HtmlUnit documentation了解更多有关使用 HtmlUnit 的信息。

Advanced MockMvcWebClientBuilder

在迄今为止的示例中,我们已经以最简单的方式使用了 MockMvcWebClientBuilder,即根据 Spring TestContext 框架为我们加载的 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
		// 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 来执行完全相同的设置,如下所示:

  • Java

  • Kotlin

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 {kotlin-issues}/KT-22208 is fixed

这种方法较为详细,但是,通过使用 MockMvc 实例构建 WebClient,我们可以随时充分利用 MockMvc 的强大功能。

有关创建 MockMvc 实例的其他信息,请参见 Configuring MockMvc