iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 24
1
Mobile Development

Android TDD 測試驅動開發系列 第 24

Day24 - Rxjava的測試

  • 分享至 

  • xImage
  •  

在上一篇呼叫WebAPI的範例,我們使用了Rxjava,這一篇要再深入介紹在使用Rxjava時應該怎麼測試。

  • Mock 一個 Observable
  • 驗證 Observable
  • 非同步
  • TestSubscriber

Mock 一個function回傳Observable

當我們遇到一個外部相依的回傳值為Observable時,直接使用Single.justObservable.just 即可。

@Test
fun getDataTest() {
    val repository = Mockito.mock(IRepository::class.java)
    `when`(repository.getSingleString()).thenReturn(Single.just("Test"))
    
    val presenter = Presenter(repository)
    presenter.getSomeBoolean()
    
    Assert.assertEquals("Test Plus", presenter.someString)
}

驗證 Observable

如果要測試一個Observable,可以使用blockingGet來取得發射的結果。

@Test
fun getDataTest() {
    val singleString = Repository().getSingleString()
    
    val expected = "Test"
    val actual = singleString.blockingGet()

    Assert.assertEquals(expected, actual)
}

也可以使用TestObserver的方式來測試。TestObserver 比起blockingGet的作法有更多的功能。

@Test
fun getDataTest2() {
    val singleString = Repository().getSingleString()

    val testObserver = TestObserver<String>()
    singleString.subscribe(testObserver)
    testObserver.assertResult("Test")
}

測試多個值的發射。

@Test
fun test(){
    val testObserver = TestObserver<String>()
    Observable.just("a", "b", "c")
        .subscribe(testObserver)

    testObserver.assertValues("a", "b", "c" )
}

測試是否完成

testObserver.assertComplete()

測試數量

testObserver.assertValueCount(2)

Schedulers

我們經常會使用Schedulers在io執行緒與MainThread切換處理不一樣的事,在單元測試就會因為在不同的執行緒而產生錯誤。

java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. 
@Test
fun testScheduler(){
    val testObserver = TestObserver<String>()

    Single.just("1")
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(testObserver)

    testObserver.assertResult("1")
}

解決的方式是在單元測試的時候使用 Schedulers.trampoline()。建立一個 ISchedulerProvider,用注入的方式讓Schedulers在執行單元測試時都是Schedulers.trampoline()

interface ISchedulerProvider {
    fun computation() = Schedulers.trampoline()
    fun mainThread() = Schedulers.trampoline()
    fun io() = Schedulers.trampoline()
}

class SchedulerProvider :ISchedulerProvider{
    override fun computation() = Schedulers.computation()
    override fun mainThread() = AndroidSchedulers.mainThread()
    override fun io() = Schedulers.io()
}

class TrampolineSchedulerProvider :ISchedulerProvider{
    override fun computation() = Schedulers.computation()
    override fun mainThread() = Schedulers.trampoline()
    override fun io() = Schedulers.trampoline()
}

測試時使用TrampolineSchedulerProvider

@Test
fun testScheduler(){
    val testObserver = TestObserver<String>()

    val schedulerProvider = TrampolineSchedulerProvider()

    Single.just("1")
        .subscribeOn(schedulerProvider.io())
        .observeOn(schedulerProvider.mainThread())
        .subscribe(testObserver)

    testObserver.assertResult("1")
}

範例下載:
https://github.com/evanchen76/RxjavaUnitTestSample


上一篇
Day23 - 使用Retrofit連接API的測試
下一篇
Day25 - Android MVP、MVVM 架構小結
系列文
Android TDD 測試驅動開發30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言