リクエストの実行
このセクションでは、MockMvcTester
を使用してリクエストを実行する方法と、AssertJ と統合してレスポンスを検証する方法を説明します。
MockMvcTester
は、静的メソッドをインポートする必要がないことを除いて、Hamcrest サポートと同じ MockHttpServletRequestBuilder
を再利用するリクエストを作成するための流れるような API を提供します。返されるビルダーは AssertJ 対応であるため、通常の assertThat()
ファクトリメソッドでラップすると、交換がトリガーされ、MvcTestResult
専用の Assert オブジェクトへのアクセスが提供されます。
以下は、/hotels/42
で POST
を実行し、Accept
ヘッダーを指定するようにリクエストを構成する簡単な例です。
Java
Kotlin
assertThat(mockMvc.post().uri("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON))
. // ...
assertThat(mockMvc.post().uri("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON))
. // ...
AssertJ は、多くの場合、交換のさまざまな部分を検証するために複数の assertThat()
ステートメントで構成されます。上記の場合のように単一のステートメントを使用するのではなく、.exchange()
を使用して、複数の assertThat
ステートメントで使用できる MvcTestResult
を返すことができます。
Java
Kotlin
MvcTestResult result = mockMvc.post().uri("/hotels/{id}", 42)
.accept(MediaType.APPLICATION_JSON).exchange();
assertThat(result). // ...
val result = mockMvc.post().uri("/hotels/{id}", 42)
.accept(MediaType.APPLICATION_JSON).exchange()
assertThat(result)
. // ...
次の例に示すように、クエリテンプレートを URI テンプレートスタイルで指定できます。
Java
Kotlin
assertThat(mockMvc.get().uri("/hotels?thing={thing}", "somewhere"))
. // ...
assertThat(mockMvc.get().uri("/hotels?thing={thing}", "somewhere"))
. // ...
次の例に示すように、クエリまたはフォームパラメーターを表すサーブレットリクエストパラメーターを追加することもできます。
Java
Kotlin
assertThat(mockMvc.get().uri("/hotels").param("thing", "somewhere"))
. // ...
assertThat(mockMvc.get().uri("/hotels").param("thing", "somewhere"))
. // ...
アプリケーションコードがサーブレットリクエストパラメーターに依存しており、クエリ文字列を明示的にチェックしない場合(ほとんどの場合)、使用するオプションは関係ありません。ただし、URI テンプレートで提供されるクエリパラメーターはデコードされますが、param(…)
メソッドを介して提供されるリクエストパラメーターはすでにデコードされていることが予想されます。
非同期
リクエストの処理が非同期で行われる場合、exchange()
はリクエストの完了を待機し、アサートする結果が実質的に不変になるようにします。デフォルトのタイムアウトは 10 秒ですが、次の例に示すように、リクエストごとに制御できます。
Java
Kotlin
assertThat(mockMvc.get().uri("/compute").exchange(Duration.ofSeconds(5)))
. // ...
assertThat(mockMvc.get().uri("/compute").exchange(Duration.ofSeconds(5)))
. // ...
生の結果を取得し、非同期リクエストのライフサイクルを自分で管理したい場合は、exchange
ではなく asyncExchange
を使用します。
マルチパート
内部的に MockMultipartHttpServletRequest
を使用するファイルアップロードリクエストを実行すると、マルチパートリクエストの実際の解析は行われません。代わりに、次の例のように設定する必要があります。
Java
Kotlin
assertThat(mockMvc.post().uri("/upload").multipart()
.file("file1.txt", "Hello".getBytes(StandardCharsets.UTF_8))
.file("file2.txt", "World".getBytes(StandardCharsets.UTF_8)))
. // ...
assertThat(mockMvc.post().uri("/upload").multipart()
.file("file1.txt", "Hello".toByteArray(StandardCharsets.UTF_8))
.file("file2.txt", "World".toByteArray(StandardCharsets.UTF_8)))
. // ...
サーブレットとコンテキストパスの使用
ほとんどの場合、コンテキスト URI とサーブレットパスはリクエスト URI から除外することをお勧めします。完全なリクエスト URI でテストする必要がある場合は、次の例に示すように、リクエストマッピングが機能するように、contextPath
と servletPath
を必ず設定してください。
Java
Kotlin
assertThat(mockMvc.get().uri("/app/main/hotels/{id}", 42)
.contextPath("/app").servletPath("/main"))
. // ...
assertThat(mockMvc.get().uri("/app/main/hotels/{id}", 42)
.contextPath("/app").servletPath("/main"))
. // ...
上記の例では、実行されたすべてのリクエストで contextPath
および servletPath
を設定するのは面倒です。代わりに、次の例に示すように、デフォルトのリクエストプロパティを設定できます。
Java
Kotlin
MockMvcTester mockMvc = MockMvcTester.of(List.of(new HotelController()),
builder -> builder.defaultRequest(get("/")
.contextPath("/app").servletPath("/main")
.accept(MediaType.APPLICATION_JSON)).build());
val mockMvc =
MockMvcTester.of(listOf(HotelController())) { builder: StandaloneMockMvcBuilder ->
builder.defaultRequest<StandaloneMockMvcBuilder>(
MockMvcRequestBuilders.get("/")
.contextPath("/app").servletPath("/main")
.accept(MediaType.APPLICATION_JSON)
).build()
}
上記のプロパティは、mockMvc
インスタンスを介して実行されるすべてのリクエストに影響します。特定のリクエストで同じプロパティが指定されている場合、デフォルト値が上書きされます。そのため、デフォルトのリクエストの HTTP メソッドと URI は重要ではありません。リクエストごとに指定する必要があるためです。