2

I am trying to unit test some Android/Kotlin code that uses RxJava2. The code looks roughly as follows:

val temperature = MutableLiveData<Double>()

fun save(): Single<Result<ClassifyResponse>> {
    val temp = temperature.value
    ...
    return repository.classify(request)
        .flatMap { response->
                val result: Result<ClassifyResponse> = Result.Success(response)
                Single.just(result)
        }.onErrorReturn {
                Result.Error(it)
        }
}

However, I am getting the following exception:

java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. See http://g.co/androidstudio/not-mocked for details.

every time I run my unit test. I read a lot of tutorials and SO answers but even after using the RxJavaPlugins, I still can't seem to be able to mock the main thread scheduler and the same exception prevails.

Could someone take a look at my unit test class and suggest what am I missing here?

class MyViewModelTest() {

    private val repository = mock(MyRepository::class.java)

    private val immediateScheduler = object : Scheduler() {
        override fun createWorker(): Worker {
            return ExecutorScheduler.ExecutorWorker(Executor { it.run() })
        }
    }

    @Before
    fun setUp() {
        RxJavaPlugins.setInitIoSchedulerHandler { immediateScheduler }
        RxJavaPlugins.setComputationSchedulerHandler { immediateScheduler }
        RxAndroidPlugins.setInitMainThreadSchedulerHandler { immediateScheduler }
        RxAndroidPlugins.setInitMainThreadSchedulerHandler { immediateScheduler }
    }

    @Test
    fun test() {
        // given temperature view model
        val viewModel = MyViewModel(repository)
        ...

        val classifyResponse = ClassifyResponse(...)
        `when`(repository.classify(any(ClassifyRequest::class.java))).then { Single.just(classifyResponse) }

        // when sending request
        val result = viewModel.save()

        // then verify result
        val expected = Result.success(classifyResponse)

        assertEquals(expected, result)
    }
}

EDIT: I noticed that it is failing due to using MutableLiveData. When I try to access temperature.value, it complains about the MainLooper thread.

michalbrz
  • 3,354
  • 1
  • 30
  • 41
Smajl
  • 7,555
  • 29
  • 108
  • 179
  • It seems everything is correct with your test. Can you show some more code, especially the code messing with threads? – michalbrz Jun 05 '18 at 14:59
  • I just noticed that it is caused by using MutableLiveData in my viewModel (and test). Is there any workaround for this as well? – Smajl Jun 05 '18 at 15:05

1 Answers1

2

Your RxJava is configured correctly and for testing MutableLiveData you need to set the rule in your tests:

@Rule
@JvmField
val rule = InstantTaskExecutorRule()

where InstantTaskExecutorRule comes from module android.arch.core:core-testing (soon to be moved to AndroidX) - as for now the latest version is 1.1.1.

michalbrz
  • 3,354
  • 1
  • 30
  • 41