MockMvc Kotlin DSL

1. 概要

このクイックチュートリアルでは、Spring Framework 5.2+で利用可能な新しいKotlin固有の_MockMvc_サポートについて説明します。
注:バージョン5.2はまだGAではないため、Spring link:/spring-maven-repository[Milestone repository]を使用する必要があります。

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オブジェクトです

    実際、見た目はきれいで、表現力豊かです。 しかし、* Kotlin DSL *を使用するとさらにクリーンになります。

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("{}") }
}
これがどのように実装されているかを確認しましょう。 まず最初に、** https://github.com/spring-projects/spring-framework/blob/master/spring-test/src/main/kotlin/org/を含むSpring Framework 5.2+を使用する必要があります。 springframework / test / web / servlet / MockMvcExtensions.kt [_MockMvcExtensions.kt_] — a_https://www.baeldung.com/kotlin-dsl [custom DSL] for _MockMvc _ ** __.__
_MockHttpServletRequestDsl_ link:/kotlin-extension-methods[extension method]で拡張関数_MockMvc.post()_を呼び出すことから始めます。
mockMvc.post("/mockmvc/validate") {
    // This is extension method's body
}
これは、_this_参照として_MockHttpServletRequestDsl_オブジェクトを使用してメソッドが実行されることを意味するため、その_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_ Kotlin DSLを使用してテストコードをクリーンにする方法を確認しました。 これは特効薬ではなく、テストコードをさらに簡潔にする小さな機能です。
これはもう1つのカスタムDSLの使用例であるため、他のプロジェクトでも同様にカスタムDSLを使用するようになります。
いつものように、この記事の完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/spring-mvc-kotlin[GitHubで]から入手できます。