Mockito说实际调用有不同的参数时使用mutableelvedata值



请阅读整个描述,我已经尽力解释了代码的每个角落。

Mockito说实际调用有不同的参数我正在测试一个更新密码函数,它的代码如下:

fun update() {
if (uiModel.validateData().isEmpty()) {
changePassword(
uiModel.oldpassword.value ?: "",
uiModel.newpassword.value ?: "",
uiModel.confirmpassword.value ?: ""
)
} else {
showToast(uiModel.validateData()[0])
}
} 

uiModel.validateData().isEmpty()这一行验证用户输入,如果它是正确的,那么它继续进入块内。uiModel.oldpassword.valueuiModel是我的支持类,它有一个mutabelive数据,通过数据绑定连接到EditTextView,它获取并设置数据到视图中。我已经模拟了uiModel类,这是一个简单的类,由dagger在viewModel构造函数中提供,这里是uiModel类代码。

class ChangePasswordUiModel @Inject constructor() {
var oldpassword = MutableLiveData<String>().default("")
var newpassword= MutableLiveData<String>().default("")
var confirmpassword= MutableLiveData<String>().default("")
}

,这里是viewModel注入设置

@ChangePasswordScope
class ChangePasswordViewModel @Inject constructor(
private val useCase: ChangePasswordUseCase,
val uiModel: ChangePasswordUiModel
) : BaseFragmentViewModel() {
}

如果验证全部设置,则调用该函数。

changePassword(uiModel.oldpassword.value ?: "",
uiModel.newpassword.value ?: "",
uiModel.confirmpassword.value ?: ""
)

实际上是这样的

var testValue = ""
private fun changePassword(oldpass: String, newpass: String, confirmPass: String) {
viewModelScope.launch {
useCase.changePassword(
oldpass,
newpass,
confirmPass
).let { result ->
when (result) {
is Result.Success -> {
testValue = "Success"
}
is Result.Exception -> showException(result.exception)
is Result.Error -> showError(parseError(result.errorBody))
else -> {
}
}
}
}
}

现在useCase.changePassword()这个函数实际上为我做了魔法,它实际上启动了网络请求,并返回给我一个自定义密封类,它有三个值Success(Any()), Error(), Exception。UseCase是这样的

interface ChangePasswordUseCase {
suspend fun changePassword(oldpassword: String, newpassword: String, confirmpassword: String): Result
}

现在测试的问题

我想在update()函数调用后检查是否调用了changepassword我的测试代码是这样的

// these are the values which set up in  @before 
val useCase = mock<ChangePasswordUseCase>()
val uiModel = mock<ChangePasswordUiModel>()  
val SUT: ChangePasswordViewModel by lazy { ChangePasswordViewModel(useCase, uiModel) }
@Test
fun `update pass validate pass and change pass`() {
val emptyLiveData = MutableLiveData("abc")
whenever(uiModel.validateData()).thenReturn(mutableListOf())
whenever(uiModel.oldpassword).thenReturn(emptyLiveData)
whenever(uiModel.confirmpassword).thenReturn(emptyLiveData)
whenever(uiModel.newpassword).thenReturn(emptyLiveData)

runBlockingTest {
whenever(
useCase.changePassword(
(emptyLiveData.value!!),
(emptyLiveData.value!!),
(emptyLiveData.value!!)
)
).thenReturn(
Result.Success(
ChangePasswordResponse()
)
)
SUT.update()
verify(useCase).changePassword(
(emptyLiveData.value!!),
(emptyLiveData.value!!),
(emptyLiveData.value!!)
)
assertThat(SUT.testValue).isEqualTo("Success")
}
}

whenever是我的扩展函数写在Mockito.when

最后这里是问题,我花了一天,但没有解决…我知道问题是值引用问题,但我不知道如何解决这个问题

误差

Argument(s) are different! Wanted:
changePasswordUseCase.changePassword(
"abc",
"abc",
"abc",
Continuation at com.trainerhub.trainer.view.home.view.change_password.ChangePasswordViewModelTest$update pass validate pass and change pass$1.invokeSuspend(ChangePasswordViewModelTest.kt:105)
);
-> at com.trainerhub.trainer.view.home.view.change_password.ChangePasswordViewModelTest$update pass validate pass and change pass$1.invokeSuspend(ChangePasswordViewModelTest.kt:102)
Actual invocation has different arguments:
changePasswordUseCase.changePassword(
"abc",
"abc",
"abc",
Continuation at com.trainerhub.trainer.view.home.view.change_password.ChangePasswordViewModel$changePassword$1.invokeSuspend(ChangePasswordViewModel.kt:61)
);
-> at com.trainerhub.trainer.view.home.view.change_password.ChangePasswordViewModel$changePassword$1.invokeSuspend(ChangePasswordViewModel.kt:58)
Comparison Failure: 
<Click to see difference>
Argument(s) are different! Wanted:
changePasswordUseCase.changePassword(
"abc",
"abc",
"abc",
Continuation at com.trainerhub.trainer.view.home.view.change_password.ChangePasswordViewModelTest$update pass validate pass and change pass$1.invokeSuspend(ChangePasswordViewModelTest.kt:105)
);
-> at com.trainerhub.trainer.view.home.view.change_password.ChangePasswordViewModelTest$update pass validate pass and change pass$1.invokeSuspend(ChangePasswordViewModelTest.kt:102)
Actual invocation has different arguments:
changePasswordUseCase.changePassword(
"abc",
"abc",
"abc",
Continuation at com.trainerhub.trainer.view.home.view.change_password.ChangePasswordViewModel$changePassword$1.invokeSuspend(ChangePasswordViewModel.kt:61)
);
-> at com.trainerhub.trainer.view.home.view.change_password.ChangePasswordViewModel$changePassword$1.invokeSuspend(ChangePasswordViewModel.kt:58)
at com.trainerhub.trainer.view.home.view.change_password.ChangePasswordViewModelTest$update pass validate pass and change pass$1.invokeSuspend(ChangePasswordViewModelTest.kt:102)
at com.trainerhub.trainer.view.home.view.change_password.ChangePasswordViewModelTest$update pass validate pass and change pass$1.invoke(ChangePasswordViewModelTest.kt)
at kotlinx.coroutines.test.TestBuildersKt$runBlockingTest$deferred$1.invokeSuspend(TestBuilders.kt:50)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.test.TestCoroutineDispatcher.dispatch(TestCoroutineDispatcher.kt:50)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:305)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:27)
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:109)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:158)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.async(Builders.common.kt:91)
at kotlinx.coroutines.BuildersKt.async(Unknown Source)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.async$default(Builders.common.kt:84)
at kotlinx.coroutines.BuildersKt.async$default(Unknown Source)
at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest(TestBuilders.kt:49)
at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest$default(TestBuilders.kt:45)
at com.trainerhub.trainer.view.home.view.change_password.ChangePasswordViewModelTest.update pass validate pass and change pass(ChangePasswordViewModelTest.kt:88)
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.rules.TestWatcher$1.evaluate(TestWatcher.java:61)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:61)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
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 com.intellij.rt.execution.CommandLineWrapper.main(CommandLineWrapper.java:64)

Process finished with exit code -1

你的代码看起来很完美。

当使用协程和挂起函数时,您将需要协程测试和mock -kotlin依赖项。
确保在build. gradde中添加了这两个依赖项。

testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2'
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"

最新更新