MockMvcKotlinDSL
1. 概要
このクイックチュートリアルでは、SpringFramework5.2以降で利用可能な新しいKotlin固有のMockMvcサポートについて説明します。
注:バージョン5.2はまだGAではないため、SpringMilestoneリポジトリを使用する必要があります。
2. テストするコントローラー
テストするコントローラーをセットアップしましょう。
次のドメインを使用します。
// Payload
data class Name(val first: String, val last: String)
// Web request
data class Request(val name: Name)
// Web response
@JsonInclude(JsonInclude.Include.NON_NULL) data class Response(val error: String?)
そして、受信したペイロードを検証するRESTコントローラー:
@RestController
@RequestMapping("/mockmvc")
class MockMvcController {
@RequestMapping(value = ["/validate"], method = [RequestMethod.POST],
produces = [MediaType.APPLICATION_JSON_VALUE])
fun validate(@RequestBody request: Request): Response {
val error = if (request.name.first == "admin") {
null
} else {
ERROR
}
return Response(error)
}
companion object {
const val ERROR = "invalid user"
}
}
ここでは、JSONにシリアル化されたカスタム Request クラスのインスタンスを受け取り、JSONにシリアル化されたカスタムResponseクラスのインスタンスを返すPOSTエンドポイントがあります。
3. 従来のテストアプローチ
標準のMockMvcアプローチを使用して、上記のコントローラーをテストできます。
mockMvc.perform(MockMvcRequestBuilders
.post("/mockmvc/validate")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(Request(Name("admin", "")))))
.andExpect(MockMvcResultMatchers.status().isOk)
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.content().string("{}"))
上記の例では、標準のテストサポートを使用して、いくつかの側面を検証しました。
- HTTP応答コードは200です
- 応答のContent-Typeはapplication/jsonです。
- 応答コンテンツは空のJSONオブジェクトです
実際、それは非常に見栄えがよく、クリーンで表現力豊かです。 ただし、 KotlinDSLを使用するとさらにクリーンにできます。
4. 最新のテストアプローチ
同じテストを次のように書き直すことができます。
mockMvc.post("/mockmvc/validate") {
contentType = MediaType.APPLICATION_JSON
content = mapper.writeValueAsString(Request(Name("admin", "")))
accept = MediaType.APPLICATION_JSON
}.andExpect {
status { isOk }
content { contentType(MediaType.APPLICATION_JSON) }
content { json("{}") }
}
これがどのように実装されているかを確認しましょう。 まず、Spring Framework 5.2+を使用する必要があります。これには、 MockMvcExtensions.kt — MockMvc。のカスタムDSLが含まれています。
まず、拡張関数 MockMvc.post()を MockHttpServletRequestDsl拡張メソッドで呼び出します。
mockMvc.post("/mockmvc/validate") {
// This is extension method's body
}
これは、メソッドがMockHttpServletRequestDslオブジェクトをthis参照として実行されることを意味します。したがって、 contentType 、 content 、およびacceptプロパティ。
次に、同様の方法で期待値を定義します— MockMvcResultMatchersDsl拡張メソッドを提供します。
andExpect {
// Extension method body
}
5. さらなる進化
さらにテストを追加したい場合は、重複を避けるために既存のコードをリファクタリングできます。
ここで一般的なコードを便利なdoTestメソッドに抽出してみましょう。
private fun doTest(input: Request, expectation: Response) {
mockMvc.post("/mockmvc/validate") {
contentType = MediaType.APPLICATION_JSON
content = mapper.writeValueAsString(input)
accept = MediaType.APPLICATION_JSON
}.andExpect {
status { isOk }
content { contentType(MediaType.APPLICATION_JSON) }
content { json(mapper.writeValueAsString(expectation)) }
}
}
これで、実際のテストが簡略化されます。
@Test
fun `when supported user is given then validation is successful`() {
doTest(Request(Name("admin", "")), Response(null))
}
@Test
fun `when unsupported user is given then validation is failed`() {
doTest(Request(Name("some-name", "some-surname")), Response(MockMvcController.ERROR))
}
6. 結論
この記事では、 MockMvc KotlinDSLを使用してテストコードをよりクリーンにする方法を確認しました。 これは特効薬ではなく、テストコードをさらに簡潔にする小さな機能です。
これはカスタムDSLの使用法のもう1つの例であるため、他のプロジェクトでもカスタムDSLの使用を開始する動機として役立ちます。
いつものように、この記事の完全なソースコードは、GitHubでから入手できます。