なぜか日本語の情報が乏しかったのでメモしておきます。
KotlinではArgumentCaptorが使えない!!
Javaの代表的なモックライブラリMockito。いろんなことができるMockitoですがその中の一つにモックのメソッドに渡したパラメータの検証を可能にするArgumentCaptor
があります。
Mockito自体は当然Kotlinでも使えるのですが、ArgumentCaptorはKotlinでは使えない!!(場合が多い)
エラーの例
具体的にはこんなコードで実行すると
class Sample {
fun testTarget(message:String, value:Int) {
println("%s%d".format(message,value))
}
}
@RunWith(PowerMockRunner::class)
@PrepareForTest(Sample::class)
class SampleTest {
val instance = PowerMockito.mock(Sample::class.java)
val messageCaptor: ArgumentCaptor<String> = ArgumentCaptor.forClass(String::class.java)
val valueCaptor: ArgumentCaptor<Int> = ArgumentCaptor.forClass(Int::class.java)
@Test
fun test() {
instance.testTarget("This is", 3)
Mockito.verify(instance,Mockito.times(1)).testTarget(messageCaptor.capture(),valueCaptor
.capture())
Assert.assertEquals("This is", messageCaptor.value)
Assert.assertEquals(1, valueCaptor.value)
}
こんなエラーが出力されます。
java.lang.IllegalStateException: messageCaptor.capture() must not be null
これの原因はエラーメッセージにもあるように「Non-NullableなパラメータにNullが入ったから」ですね。
KotlinのNull安全な仕様が裏目に……
そう、ArgumentCaptor.capture()
はNullを返すのです。JavaはパラメータのNullチェックをしないので問題ありませんでしたが、KotlinはNullチェックしてくれます。その優しさが裏目に出てしまったのです。
もちろんメソッドのパラメータをNon-Nullableにすれば実行できます。しかしそれでは本末転倒です。
mockito-kotlinを使う
その解決策がmockito-kotlinを使うことです。
mockito-kotlinのcapture()
を使うことでキャプチャしつつテストメソッドには値をそのまま渡すことができます。
@RunWith(PowerMockRunner::class)
@PrepareForTest(Sample::class)
class SampleTest {
val instance = PowerMockito.mock(Sample::class.java)
val messageCaptor: ArgumentCaptor<String> = ArgumentCaptor.forClass(String::class.java)
val valueCaptor: ArgumentCaptor<Int> = ArgumentCaptor.forClass(Int::class.java)
@Test
fun test() {
instance.testTarget("This is", 3)
//ArgumentCaptor.capture()は使わずにmockito_kotlin.capture()を使う
//mockito_kotlin.capture()の引数はArgumentCaptorのインスタンスをそのまま入れれば良い
Mockito.verify(instance,Mockito.times(1)).testTarget(capture(messageCaptor),capture(valueCaptor))
Assert.assertEquals("This is", messageCaptor.value)
Assert.assertEquals(3, valueCaptor.value)
}
}
お手軽簡単ですね。
mockito-kotlinはMockitoをよりKotlinぽく使うためのライブラリのようですが、私のように「Javaで覚えた書き方そのまま使いたい」という面倒くさがり屋にも大変有用です。