MockMvc 和 HtmlUnit

本节介绍如何集成 MockMvc 和 HtmlUnit。如果你想使用原始的 HtmlUnit 库,请使用此选项。

MockMvc 和 HtmlUnit 设置

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

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

WebClient webClient;

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

这确保了任何引用 localhost 作为服务器的 URL 都会被定向到我们的 MockMvc 实例,而无需真正的 HTTP 连接。任何其他 URL 都会像往常一样使用网络连接请求。这让我们能够轻松测试 CDN 的使用。

MockMvc 和 HtmlUnit 用法

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

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

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

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

最后,我们可以验证新消息是否成功创建。以下断言使用 AssertJ 库:

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("Infra Rocks");
String text = newMessagePage.getHtmlElementById("text").getTextContent();
assertThat(text).isEqualTo("In case you didn't know, Infra Rocks!");

前面的代码在很多方面改进了我们的 MockMvc 测试。 首先,我们不再需要显式验证表单,然后创建一个看起来像表单的请求。相反,我们请求表单,填写并提交,从而大大减少了开销。

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

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

高级 MockMvcWebClientBuilder

到目前为止的示例中,我们以最简单的方式使用了 MockMvcWebClientBuilder,即基于 Infra TestContext 框架为我们加载的 WebApplicationContext 构建 WebClient。此方法在以下示例中重复:

WebClient webClient;

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

我们还可以指定其他配置选项,如下例所示:

WebClient webClient;

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

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

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

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

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