AndroidでRxを利用したクラスのテストをする際にちょっと手間だったことがあったので拡張関数を作ってみました。
※junit, robolectric, mockito, AssertionLibraryはkluentを利用しています。
面倒だったこと
テスト対象
- 通信して結果を取ってくるHogeUseCaseがあるとして、そのテストをしたい。
- HogeUseCaseは結果をSingleで返してくるとする。
- HogeUseCaseにはHogeRepositoryをDIでInjectしている。
HogeUseCase.kt
class HogeUseCase @Inject constructor(private val repository: HogeRepository) {
fun requestHoge(): Single<HogeResponse> {
return repository.requestHoge().subscribeOn(Schedulers.io())
}
}
テストクラス
テストを書くと下記のようになります。
HogeUseCaseTest.kt
class HogeUseCaseTest {
private val hogeRepository: HogeRepository = mock()
@Test
fun requestHogeTest() {
whenever(hogeRepository.requestHoge()).thenReturn(Single.just(HogeResponse("connection success", "200")))
HogeUseCase(mock())
.requestHoge()
.test()
.assertNoErrors()
.assertValue { response ->
try {
response.message shouldEqual "connection success"
response.resultCode shouldEqual "200"
true
} catch (e: AssertionError) {
e.printStackTrace()
false
}
}
}
assertValueは処理ブロックを渡すことで中で要素の検証をするのですが、テスト成否をtrue/falseで返さなければなりません。
なので、中で検証するとなると、AssertionErrorをcatchした上でfalseを返す必要があります。
これが面倒だったので拡張関数化してみました。
作った拡張関数
assertValueはBaseTestConsumerにあるので、そこに拡張関数を作ります。
BaseTestConsumerExt.kt
fun <T, U : BaseTestConsumer<T, U>> BaseTestConsumer<T, U>.assertValueWith(verification: (T) -> Unit): U {
return assertValue {
try {
verification(it)
return@assertValue true
} catch (e: AssertionError) {
e.printStackTrace()
return@assertValue false
}
}
}
使い方
@Test
fun requestHogeTest() {
whenever(hogeRepository.requestHoge()).thenReturn(Single.just(HogeResponse("connection success", "200")))
HogeUseCase(mock())
.requestHoge()
.test()
.assertNoErrors()
.assertValueWith { response ->
response.message shouldEqual "connection success"
response.resultCode shouldEqual "200"
}
最後に
少し面倒だった処理を拡張関数にしてスッキリさせてみました。
もっといいやり方や、メソッドが用意されているなどありましたら教えていただけると幸いです。