👋
KotlinのMethodSourceのParametrizedTestを見やすく書く
Kotlinでテストを書く際に、MethodSource
を使ったParametrizedTestをより可読性高く書く方法を紹介します。本記事では、課題とその解決方法を具体的なサンプルコードとともに解説します。
🚨 課題
MethodSource
を利用する際、JavaではStaticメソッドとして記述する必要があります。しかし、KotlinではStaticメソッドの代わりにCompanion Object
を使って定義することになります。
Companion Objectの課題
-
inner classでは定義できない
Companion Objectはテストクラスのトップレベルでしか定義できません。そのため、テストケースとMethodSource
の距離が離れ、可読性が低下するという問題があります。
✅ 解決方法
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
を活用
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
アノテーションを利用することで、MethodSource
をテストケースに近いinner class内のインスタンスメソッドとして定義できます。これにより、テストコードの可読性が向上します。
🧪 サンプルコード
以下は、@TestInstance
を活用してMethodSource
をinner classのインスタンスメソッドとして定義したサンプルコードです。
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.MethodSource
import java.util.stream.Stream
class PendingExtensionFieldsTest {
@Nested
@TestInstance(TestInstance.Lifecycle.PER_CLASS) // Allow MethodSource to be instance method close to the testcase.
inner class GetByIdTest {
@ParameterizedTest
@MethodSource("extensionFieldsProvider")
fun `returns the extension field corresponding to the given id`(
fieldsUnderTest: PendingExtensionFields,
fieldId: Int, // value class is recognized as Raw Tyep via MethodSource
expected: ExtensionField?
) {
// Given / When / Then
assertThat(fieldsUnderTest.getByExtensionFieldId(ExtensionFieldId(fieldId))).isEqualTo(expected)
}
private fun extensionFieldsProvider(): Stream<Arguments> {
val field1 = ExtensionField1("value")
val field2 = ExtensionField2("value")
val field3 = ExtensionField3("value")
val field4 = ExtensionField4("value")
val field5 = ExtensionField5("value")
val field6 = ExtensionField6("value")
val field7 = ExtensionField7("value")
val field8 = ExtensionField8("value")
val field9 = ExtensionField9("value")
val field10 = ExtensionField10("value")
val field11 = ExtensionField11("value")
val field12 = ExtensionField12("value")
val field13 = ExtensionField13("value")
val field14 = ExtensionField14("value")
val field15 = ExtensionField15("value")
val field16 = ExtensionField16("value")
val field17 = ExtensionField17("value")
val field18 = ExtensionField18("value")
val field19 = ExtensionField19("value")
return Stream.of(
Arguments.of(PendingExtensionFields(field1 = field1), 1, field1),
Arguments.of(PendingExtensionFields(field2 = field2), 2, field2),
Arguments.of(PendingExtensionFields(field3 = field3), 3, field3),
Arguments.of(PendingExtensionFields(field4 = field4), 4, field4),
Arguments.of(PendingExtensionFields(field5 = field5), 5, field5),
Arguments.of(PendingExtensionFields(field6 = field6), 6, field6),
Arguments.of(PendingExtensionFields(field7 = field7), 7, field7),
Arguments.of(PendingExtensionFields(field8 = field8), 8, field8),
Arguments.of(PendingExtensionFields(field9 = field9), 9, field9),
Arguments.of(PendingExtensionFields(field10 = field10), 10, field10),
Arguments.of(PendingExtensionFields(field11 = field11), 11, field11),
Arguments.of(PendingExtensionFields(field12 = field12), 12, field12),
Arguments.of(PendingExtensionFields(field13 = field13), 13, field13),
Arguments.of(PendingExtensionFields(field14 = field14), 14, field14),
Arguments.of(PendingExtensionFields(field15 = field15), 15, field15),
Arguments.of(PendingExtensionFields(field16 = field16), 16, field16),
Arguments.of(PendingExtensionFields(field17 = field17), 17, field17),
Arguments.of(PendingExtensionFields(field18 = field18), 18, field18),
Arguments.of(PendingExtensionFields(field19 = field19), 19, field19),
Arguments.of(PendingExtensionFields(), 20, null),
)
}
}
}
Discussion