运行 JUnit4 测试时出现 NullPointerException,使用 MockitoHint "Unused..." 和 "args ok?"
NullPointerException when running JUnit4 test, with MockitoHint "Unused..." and "args ok?"
我正在尝试 运行 此 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.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()
}
)
}
我是单元测试的新手,对此我完全感到困惑,尤其是在我通过了一个类似的测试之后。这将测试另一个名为 uiState
的 LiveData
对象
@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)
}
通过首先将我的测试更改为使用 any
来解决它,这导致 any(GithubUser::class.java) must not be null
错误消息。然后我使用以下函数找到了这个 SO post:
fun <T> any(): T = Mockito.any<T>()
所以我将之前的函数添加到我的测试中 class 并将我的测试更改为如下所示:
@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))
}
我正在尝试 运行 此 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.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()
}
)
}
我是单元测试的新手,对此我完全感到困惑,尤其是在我通过了一个类似的测试之后。这将测试另一个名为 uiState
LiveData
对象
@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)
}
通过首先将我的测试更改为使用 any
来解决它,这导致 any(GithubUser::class.java) must not be null
错误消息。然后我使用以下函数找到了这个 SO post:
fun <T> any(): T = Mockito.any<T>()
所以我将之前的函数添加到我的测试中 class 并将我的测试更改为如下所示:
@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))
}