Robolectric 测试和 LiveData

Robolectric test and LiveData

为了全面掌握 Kotlin、LiveData 和 Robolectric,我得到了一个简单的启动画面 activity。

在运行应用时可以正常运行,但在测试中无法运行。就像永远不会触发实时数据的回调一样,或者如果没有为其注册观察者。

这是测试:

@Test
fun should_redirect_to_login_when_time_is_up_after_onStart() {
    val timeUp = MutableLiveData<Boolean>()

    kodein.addConfig {
        bind<SplashViewModel>(overrides = true) with factory {
            _: BaseActivity -> mock<SplashViewModel> { on { isTimeUp() } doReturn timeUp }
        }
    }

    val activity = Robolectric.buildActivity(SplashActivity::class.java).create().start().resume().get()
    timeUp.value = true

    val startedIntent = shadowOf(activity).nextStartedActivity
    assertThat(startedIntent).isNotNull
    assertThat(startedIntent).hasComponent(application.packageName, LoginActivity::class.java)
}

activity:

class SplashActivity : JapetActivity() {

    lateinit var viewModel: SplashViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_splash)

        viewModel = kodein.with(this).instance()
        viewModel.isTimeUp().observe(this, Observer<Boolean?> { b -> transitionIfTimeUp(b ?: false) })

        transitionIfTimeUp(viewModel.isTimeUp().value ?: false)
    }

    private fun transitionIfTimeUp(isTimeUp: Boolean) {
        if (isTimeUp) {
            startActivity(Intent(this, LoginActivity::class.java))
            finish()
        }
    }
}

视图模型(无论如何都会被模拟,所以不使用实现):

/**
 * ViewModel for data of the splash screen
 */
interface SplashViewModel {

    /** Have we shown the splash screen long enough? */
    fun isTimeUp(): LiveData<Boolean>
}

/**
 * Default implementation of the view model
 */
class SplashViewModelImpl : ViewModel(), SplashViewModel {

    companion object {
        private const val SPLASH_DURATION_MS = 2000L
    }

    private val isTimeUp = MutableLiveData<Boolean>()

    init {
        isTimeUp.value = false

        Observable.timer(SplashViewModelImpl.SPLASH_DURATION_MS, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .subscribe { isTimeUp.value = true }
    }

    override fun isTimeUp(): LiveData<Boolean> = isTimeUp
}

看起来 Robolectric 没有触发 Android 生命周期方法,所以 LiveData 不会更新观察者。 activity 由 Robolectric 创建后,我可以通过手动触发 "ON_START" 生命周期事件来解决此问题:

activity.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START)