KotlinでJUnit5を使ってデータドリブンテストを整備する


今回は自身で開発・運営している「Hello Books」で利用している技術について紹介したいと思います。

Hello Booksについて

  • エンジニア向け技術書レビューサービス
  • 購入前の判断にエンジニアのレビューを役立てることができる
  • アカウントを作成することで自身もレビューを投稿したり、技術書をブックマークしたりできる
  • 詳細な条件による技術書の検索が可能

@ParameterizedTest@MethodSourceでデータドリブン化

業務ではPHPを使っているのですが、DDD(ドメイン駆動設計)でValueObjectの単体テストを記述する際にはPHPDocを利用したデータドリブンにテストを記述しています。Kotlinでも同じ様にデータドリブンテストを実現する方法がないかなと探していたところ、JUnit5の@ParameterizedTestアノテーションを使うことで簡単に記述できることが分かりました。

JUnitでは@Testを記述することでテストケースを作成することができますが、データドリブンなテストケースを作成する場合には@ParameterizedTestを記述します。

class BookTitleTest {
    @ParameterizedTest
    @MethodSource("dataProvider")
    fun testValidation(value: String, isValid: Boolean) {
        when (isValid) {
            true -> assertDoesNotThrow { BookTitle(value) }
            false -> assertThrows<ConstraintViolationException> { BookTitle(value) }
        }
    }
    companion object {
        @JvmStatic
        fun dataProvider() = listOf(
                // 正常系
                Arguments.of("test title", true),
                Arguments.of("a", true),
                Arguments.of("a".repeat(50), true),
                // 異常系
                Arguments.of("", false),
                Arguments.of("a".repeat(51), false)
        )
    }
}

上記の様にすることで、dataProviderメソッドをソースとするデータドリブンテストとしてtestValidationを記述することができます。

dataProviderメソッドではtestValidationテストで受け取る2つの引数として渡す値を設定します。今回は1つ目の引数ValueをString、2つ目の引数isValidをBooleanとして設定しているので、設定する値はArguments.of("test title", true)の様になります。 任意の数のデータを任意の型としてソースから受け取ることができるのはとても便利ですね。

テストを実行して、各パラメータのテスト結果を確認してみます。IntelliJでは各ケースで渡された値とそのテスト結果を一目で確認することができます。

Kotlinで記述する際の注意点

とてもシンプルに利用できる@ParameterizedTestですが、Kotlinで利用する際には2つ注意点があります。

①ソースメソッドをcompanion objectとして記述する

@MethodSourceとして設定されるメソッドはstaticとして記述される必要があります。Kotlinではstaticが存在しないため、代替方法としてcompanion objectとしてソースになるメソッドを記述する必要があります。

②ソースメソッドに@JvmStaticを記述する

Kotlinでcompanion objectとして記述されたメソッドはJavaとして扱われる際にCompanionクラスを経由しないとアクセスすることができません。今回の例で言うと、ソースメソッドにアクセスするにはBookTitleTest.Companion.dataProvider()とする必要があるわけです。このままではJavaが「BookTitleTest.dataProvider()どこにもないよ、、」と困ってしまうので、@JvmStaticアノテーションを付記してあげる必要があります。こうすることで、Companionを経由しなくてもメソッドを呼び出せる様になります。

まとめ

どうしてもデータドリブンテストを書きたくて、TestNGなどの外部フレームワークを利用しなくちゃダメかなと思い調べていたところ、JUnit5であれば非常に簡単に実現できて感動しました。皆様もぜひお試しください!