我正在使用Android数据绑定来侦听实时数据更改,并且我想观察viewmodel级别的更改(而不是观察片段,然后将回调发送到viewmodel)
observerForever
很有趣,因为它对我有用。但是,当我运行测试时,出现以下错误:
java.lang.NullPointerException
at androidx.arch.core.executor.DefaultTaskExecutor.isMainThread(DefaultTaskExecutor.java:77)
at androidx.arch.core.executor.ArchTaskExecutor.isMainThread(ArchTaskExecutor.java:116)
at androidx.lifecycle.LiveData.assertMainThread(LiveData.java:461)
at androidx.lifecycle.LiveData.observeForever(LiveData.java:222)
at com.bcgdv.ber.maha.login.ui.LoginViewModel.<init>(LoginViewModel.kt:43)
at com.bcgdv.ber.maha.login.ui.LoginViewModelTest.<init>(LoginViewModelTest.kt:26)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.junit.platform.commons.util.ReflectionUtils.newInstance(ReflectionUtils.java:443)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:60)
我的代码在viewmodel类中如下:
val observerEmail: Observer<String> = Observer {
setEmailError(it)
checkLoginButton()
}
var email = MutableLiveData<String>()
init {
email.observeForever(observerEmail)
}
还要注意的是,我正在使用Junit5。
@ExtendWith(InstantTaskExecutorExtension::class)
class LoginViewModelTest {
val emailAddress = "xyz@xyz.com"
val password = "password"
val user: User = User("1", "xyz@xyz.com", "password")
val loginUsecase: LoginUseCase = mock {
on { loginUser(emailAddress, password) } doReturn (Single.just(user))
}
private val loginViewModel: LoginViewModel = LoginViewModel(
loginUsecase,
LoginCredentialsValidator(),
Schedulers.trampoline(),
Schedulers.trampoline()
)
@Test
fun should_return_user_as_null_initially() {
whenever(loginUsecase.getUser()).thenReturn(null)
loginViewModel.init()
assertEquals(
expected = null,
actual = loginViewModel.obsEmail.get()
)
}}
这是InstantTaskExecutorExtension。
class InstantTaskExecutorExtension : BeforeEachCallback, AfterEachCallback {
override fun beforeEach(context: ExtensionContext?) {
ArchTaskExecutor.getInstance()
.setDelegate(object : TaskExecutor() {
override fun executeOnDiskIO(runnable: Runnable) = runnable.run()
override fun postToMainThread(runnable: Runnable) = runnable.run()
override fun isMainThread(): Boolean = true
})
}
override fun afterEach(context: ExtensionContext?) {
ArchTaskExecutor.getInstance().setDelegate(null)
}
}
答案 0 :(得分:0)
通常,建议仅将LiveData用于View模型<-> View通讯,但是我认为问题是:
private val loginViewModel: LoginViewModel = LoginViewModel(
...
)
由于这是一个成员变量,因此它将在测试之前执行,并且由于调用构造函数而已隐式执行init()
。
无需显式调用init()
。我将删除loginViewModel
成员变量,并通过构造函数在测试函数中实例化它:
@Test
fun should_return_user_as_null_initially() {
...
LoginViewModel(
...
)
...
}