【问题标题】:NullPointerException when running JUnit4 test, with MockitoHint "Unused..." and "args ok?"运行 JUnit4 测试时出现 NullPointerException,MockitoHint "Unused..." 和 "args ok?"
【发布时间】:2020-08-07 07:37:14
【问题描述】:

我正在尝试运行此 JUnit 4 测试以检查名为 dbState 的对象的正确 LiveData 值:

    @Test
fun `saveNoteToDb - correct DB states`() {
    val dbStatus = SUT.dbState?.testObserver()
    val githubUser = GithubUser("", "")

    `when`(insertUserUseCase.insert(githubUser))
        .thenReturn(Completable.complete())

    SUT.saveNoteToDb("", "")

    Truth.assert_()
        .that(dbStatus?.observedValues)
        .isEqualTo(listOf(DB_SAVING, NOTE_SAVED))
}

但我得到了一个NullPointerException,Mockito 添加了一些不太有用的提示:

[MockitoHint] ProfileViewModelTest.saveNoteToDb - correct DB states (see javadoc for MockitoHint):
[MockitoHint] 1. Unused... -> at com.something.someapp.ui.profile.ProfileViewModelTest.saveNoteToDb - correct DB states(ProfileViewModelTest.kt:88)
[MockitoHint]  ...args ok? -> at com.something.someapp.ui.profile.ProfileViewModel.saveNoteToDb(ProfileViewModel.kt:54)


java.lang.NullPointerException
    at com.something.someapp.ui.profile.ProfileViewModel.saveNoteToDb(ProfileViewModel.kt:55)
    at com.something.someapp.ui.profile.ProfileViewModelTest.saveNoteToDb - correct DB states(ProfileViewModelTest.kt:91)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)

被测试的函数如下所示:

    fun saveNoteToDb(userName: String, note: String) {
        compositeDisposable += insertUserUseCase.insert(GithubUser(userName, note))
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .doOnSubscribe { _dbState.value = DB_SAVING }
            .subscribeBy(
                onComplete = { _dbState.value = NOTE_SAVED },
                onError = {
                    _dbState.value = it.message?.let { msg -> DB_ERROR(msg) }
                    it.printStackTrace()
                }
            )
    }

我是单元测试的新手,对此我完全感到困惑,特别是因为我做了一个类似的测试通过了。这将测试另一个名为 uiStateLiveData 对象

    @Test
    fun `fetchUserDetails - correct UI states`() {
        val uiStatus = SUT.uiState?.testObserver()

        `when`(searchUserUseCase.searchForUser("username")).thenReturn(Single.just(
            SearchUserResponse()
        ))

        SUT.fetchUserDetails("username")

        Truth.assert_()
            .that(uiStatus?.observedValues)
            .isEqualTo(listOf(LOADING, SUCCESS))
    }

这是之前成功测试的正在测试的功能:

    fun fetchUserDetails(userName: String) {
        compositeDisposable += searchUserUseCase.searchForUser(userName)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .doOnSubscribe { _uiState.value = LOADING }
            .subscribeBy(
                onSuccess = {
                    followers.set(it.followers.toString())
                    following.set(it.following.toString())
                    name.set(it.name)
                    location.set(it.location)
                    _uiState.value = SUCCESS
                },
                onError = { error ->
                    error.printStackTrace()
                    _uiState.value = error.message?.let {
                        ERROR(it)
                    }
                }
            )
    }

testObserver 长这样,供参考:

open class TestObserver<T> : Observer<T> {

    val observedValues = mutableListOf<T?>()

    override fun onChanged(value: T?) {
        observedValues.add(value)
    }
}

fun <T> LiveData<T>.testObserver() = TestObserver<T>().also {
    observeForever(it)
}

【问题讨论】:

    标签: android unit-testing mockito junit4 android-livedata


    【解决方案1】:

    通过首先将我的测试更改为使用any 解决了这个问题,这导致了 any(GithubUser::class.java) must not be null 错误消息。然后我使用以下函数找到了这个SO post

    fun <T> any(): T = Mockito.any<T>()
    

    所以我将之前的函数添加到我的测试类中,并将我的测试更改为如下所示:

        @Test
        fun `saveNoteToDb - correct DB states`() {
            val dbStatus = SUT.dbState?.testObserver()
    
            `when`(insertUserUseCase.insert(any()))
                .thenReturn(Completable.complete())
    
            SUT.saveNoteToDb("", "")
    
            Truth.assert_()
                .that(dbStatus?.observedValues)
                .isEqualTo(listOf(DB_SAVING, NOTE_SAVED))
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-20
      • 2021-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多