【问题标题】:Unit testing LiveData observerForever results in NullPointer Exception with Junit5单元测试 LiveData observerForever 导致 Junit5 出现 NullPointer 异常
【发布时间】:2020-08-18 06:42:09
【问题描述】:

我正在使用 Android 数据绑定来监听实时数据变化,我想观察视图模型级别的变化(而不是观察片段,然后向视图模型发送回调) 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)
}

}

【问题讨论】:

  • 这能回答你的问题吗? MutableLiveData is null in JUnitTest
  • @BhavikKasundra 我试过了。我仍然收到错误消息。
  • @SoH 我也遇到了同样的问题,你找到解决办法了吗。
  • 我最终没有使用 init。另外我没有使用livedata。而是使用可观察字段并将它们与 rxjava 发布主题挂钩
  • 您能否仔细检查一下您的@Test 注释是否来自JUnit5 jupiter 包?那件事发生在我身上......

标签: android junit data-binding android-livedata observer-pattern


【解决方案1】:

一般建议仅将 LiveData 用于 View Model View 通信,但我认为问题是:

private val loginViewModel: LoginViewModel = LoginViewModel(
    ...
)

因为这是一个成员变量,它会在测试之前执行,并且它已经隐式执行init(),因为你调用了构造函数。 无需显式调用init()。我会删除 loginViewModel 成员变量并通过构造函数在测试函数中实例化它:

@Test
fun should_return_user_as_null_initially() {
    ...
    LoginViewModel(
       ...
    )
    ...
}

【讨论】:

  • 对我的答案进行了更改。我已经在使用任务扩展。仍然遇到同样的问题。我在视图模型本身中使用observeForever。在 init 方法中。
猜你喜欢
  • 2019-04-11
  • 1970-01-01
  • 1970-01-01
  • 2017-05-11
  • 1970-01-01
  • 2021-07-27
  • 2015-04-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多