kako.dev

開発、自作アプリのこと

JUnitのパラメタライズドテスト

社の読書会で「単体テストの考え方/使い方」を読んでます。

本書の中でパラメタライズドテスト(パラメータ化テスト)について紹介されており、JUnitでどのように書くのか調べました。

いくつかパターンがあったのでそれぞれ紹介します。

※JUnitでのパラメタライズドテストを紹介しているだけで、パラメタライズドテストを強く推奨している意図はありません。

JUnit4のParameterized

JUnit4にParameterizedクラスがありそれを使う方法

@RunWith(Parameterized::class)
class SquaredTestJUnit4ParameterizeTest {
    companion object {
        @Parameters
        @JvmStatic
        fun getData() = arrayOf<Squared>(
            Squared(1, 1),
            Squared(2, 4),
            Squared(3, 9)
        )
    }

    @Parameter(0)
    lateinit var data: Squared

    @Test
    fun test() {
        assertEquals(data.expected, data.input * data.input)
    }
}

data class Squared(
    val input: Int,
    val expected: Int
)

まずは、対象となるテストクラスに @RunWith(Parameterized::class) を付けます。 次にテストデータを定義します。データに@Parametersを付けます。ここはstaticにする必要があります。

渡されるデータを受け取りたい変数に@Parameterを付けることでテスト実行時にテストデータが格納されます。 渡されるデータがIteratorの場合、@Parameterの引数に数値を渡すことでそのIndexのデータを受け取れます。(デフォルトは0)

実行結果を見てみるとデータの分だけテストが実行されていることがわかります。

JUnit4のTheory

次は別の方法で@Theoryを使う方法

@RunWith(Theories::class)
class SquaredTestJUnit4TheoryTest {
    companion object {
        @JvmStatic
        @DataPoints
        fun data() = listOf(
            Squared(1, 1),
            Squared(2, 4),
            Squared(3, 9)
        )
    }

    @Theory
    fun test(data: Squared) {
        println("input: " + data.input + "expected: " + data.expected)
        Assert.assertEquals(data.expected, data.input * data.input)
    }
}

こちらは、対象となるテストクラスに @RunWith(Theories::class) を付けます。 渡すデータには@DataPointsを付けます。この時もstaticにする必要があります。

テストメソッドには@Testではなく、@Theoryをつけます。 テストメソッドの引数には受け取るデータを指定します。(ここではSquared)

実行すると以下のような結果になります。

1つしか実行されてないように見えますが、printなどして確認して見るとちゃんとデータ分実行されています。(なんともわかりにくい)

Junit5のParameterizedTest

(これが一番よさげ) 上2つの方法はJUni4でしたが、JUnit5が使えるならこの方法がシンプルでいいです。

class SquaredTestJUnit5 {
    companion object {
        @JvmStatic
        fun squaredTestProvider(): Stream<Squared> = Stream.of(
            Squared(1, 1),
            Squared(2, 4),
            Squared(3, 9)
        )
    }

    @ParameterizedTest
    @MethodSource("squaredTestProvider")
    fun test(data: Squared) {
        Assertions.assertEquals(data.expected, data.input * data.input)
    }
}

渡すテストデータはStream<T> で宣言でき渡したいデータをstaticな関数で定義します。 テストメソッドには@ParameterizedTest を付けます。データには@MethodSource を付けることで受け取れます。 (引数にテストデータを返す関数名を文字列で渡します。ここではsquaredTestProvider)

@MethodSource のほかにも@ValueSource@CSVSourceなどあります。

実行結果を見るとこのようになります。

参考

Parameterized tests · junit-team/junit4 Wiki · GitHub

Theories · junit-team/junit4 Wiki · GitHub

JUnit 5 User Guide

GitHub - mannodermaus/android-junit5: Testing with JUnit 5 for Android.