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 が、実際の HTTP 接続を必要とせずに MockMvc インスタンスにリダイレクトされるようになります。他の URL は、通常どおりネットワーク接続を使用してリクエストされます。これにより、CDN の使用を簡単にテストできます。

MockMvc および HtmlUnit の使用箇所

これで、通常どおり HtmlUnit を使用できますが、アプリケーションをサーブレットコンテナーにデプロイする必要はありません。例: 次のメッセージを作成するためにビューをリクエストできます:

  • 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 テストを改善しています。まず、フォームを明示的に検証してから、フォームのようなリクエストを作成する必要がなくなりました。代わりに、フォームをリクエストし、記入し、送信することにより、オーバーヘッドを大幅に削減します。

もう 1 つの重要な要素は、HtmlUnit は Mozilla Rhino エンジンを使用します (英語) が JavaScript を評価することです。つまり、ページ内で JavaScript の動作をテストすることもできます。

HtmlUnit の使用に関する追加情報については、HtmlUnit ドキュメント (英語) を参照してください。

高度な MockMvcWebClientBuilder

これまでの例では、Spring TestContext フレームワークによってロードされた WebApplicationContext に基づいて WebClient を構築することにより、可能な限り最も簡単な方法で MockMvcWebClientBuilder を使用しました。このアプローチは、次の例で繰り返されます。

  • 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 インスタンスの作成に関する追加情報については、セットアップの選択を参照してください。