MockMvc and HtmlUnit

This section describes how to integrate MockMvc and HtmlUnit. Use this option if you want to use the raw HtmlUnit libraries.

MockMvc and HtmlUnit Setup

First, make sure that you have included a test dependency on org.htmlunit:htmlunit.

We can easily create an HtmlUnit WebClient that integrates with MockMvc by using the MockMvcWebClientBuilder, as follows:

WebClient webClient;

@BeforeEach
void setup(WebApplicationContext context) {
  webClient = MockMvcWebClientBuilder
      .webAppContextSetup(context)
      .build();
}
This is a simple example of using MockMvcWebClientBuilder. For advanced usage, see Advanced MockMvcWebClientBuilder.

This ensures that any URL that references localhost as the server is directed to our MockMvc instance without the need for a real HTTP connection. Any other URL is requested by using a network connection, as normal. This lets us easily test the use of CDNs.

MockMvc and HtmlUnit Usage

Now we can use HtmlUnit as we normally would but without the need to deploy our application to a Servlet container. For example, we can request the view to create a message with the following:

HtmlPage createMsgFormPage = webClient.getPage("http://localhost/messages/form");
The default context path is "". Alternatively, we can specify the context path, as described in Advanced MockMvcWebClientBuilder.

Once we have a reference to the HtmlPage, we can then fill out the form and submit it to create a message, as the following example shows:

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

Finally, we can verify that a new message was created successfully. The following assertions use the AssertJ library:

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!");

The preceding code improves on our MockMvc test in a number of ways. First, we no longer have to explicitly verify our form and then create a request that looks like the form. Instead, we request the form, fill it out, and submit it, thereby significantly reducing the overhead.

Another important factor is that HtmlUnit uses the Mozilla Rhino engine to evaluate JavaScript. This means that we can also test the behavior of JavaScript within our pages.

See the HtmlUnit documentation for additional information about using HtmlUnit.

Advanced MockMvcWebClientBuilder

In the examples so far, we have used MockMvcWebClientBuilder in the simplest way possible, by building a WebClient based on the WebApplicationContext loaded for us by the Infra TestContext Framework. This approach is repeated in the following example:

WebClient webClient;

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

We can also specify additional configuration options, as the following example shows:

WebClient webClient;

@BeforeEach
void setup() {
  webClient = MockMvcWebClientBuilder
    // demonstrates applying a MockMvcConfigurer (Infra 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();
}

As an alternative, we can perform the exact same setup by configuring the MockMvc instance separately and supplying it to the MockMvcWebClientBuilder, as follows:

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

This is more verbose, but, by building the WebClient with a MockMvc instance, we have the full power of MockMvc at our fingertips.

For additional information on creating a MockMvc instance, see Setup Choices.