You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决SignUpViewModel测试中的TooManyActualInvocations错误

问题解决:SignUpViewModel测试中的TooManyActualInvocations错误

错误原因

测试代码中手动调用了一次repository.registerAccount(dummyName, dummyEmail, dummyPassword),而执行signUpViewModel.registerAccount时,ViewModel内部又会调用一次该方法,导致该方法实际被执行2次,但Mockito的verify默认只期望方法被调用1次,因此触发了TooManyActualInvocations错误。

另外,测试中直接将LiveData对象与dummyRegisterResponse比较是错误的,应该获取LiveData的实际值进行断言。

修正后的测试代码

@ExperimentalCoroutinesApi
@RunWith(MockitoJUnitRunner::class)
class SignUpViewModelTest {
    @get:Rule
    val instantExecutorRule = InstantTaskExecutorRule()

    @get:Rule
    var mainDispatcherRule = MainDispatcherRule()

    @Mock
    private lateinit var repository: Repository
    private lateinit var signUpViewModel: SignUpViewModel

    private val dummyRegisterResponse = DataDummy.generateDummyRegisterResponse()
    private val dummyName = "Full Name"
    private val dummyEmail = "email@mail.com"
    private val dummyPassword = "password"

    @Before
    fun setUp() {
        signUpViewModel = SignUpViewModel(repository)
    }

    @Test
    fun standartTest() = runTest {
        val obj = MutableLiveData<RegisterResponse>()
        obj.value = dummyRegisterResponse
        // 预设Repository的registerResponse返回值
        Mockito.`when`(repository.registerResponse).thenReturn(obj)
        
        // 调用ViewModel的方法,内部会触发Repository的registerAccount
        signUpViewModel.registerAccount(dummyName, dummyEmail,dummyPassword)
        
        // 验证Repository的registerAccount只被调用一次
        verify(repository).registerAccount(dummyName, dummyEmail, dummyPassword)
        
        // 获取LiveData的值并断言
        val actualResponseValue = signUpViewModel.registerResponse.value
        Assert.assertNotNull(actualResponseValue)
        Assert.assertEquals(dummyRegisterResponse, actualResponseValue)
    }
}

关键修正点

  1. 移除手动调用的repository.registerAccount:ViewModel的registerAccount方法已经会触发该调用,无需手动执行。
  2. 修正LiveData断言逻辑:通过signUpViewModel.registerResponse.value获取LiveData的当前值,再与假数据比较。
  3. 保持Mock预设的顺序:先通过Mockito.when预设Repository的返回值,再调用ViewModel的方法,确保Mock行为生效。

额外说明

由于Repository的registerAccount是基于Retrofit的异步回调实现,在测试Mock对象时,我们不需要关心内部的异步逻辑,只需要预设registerResponse的返回值即可,因为Mock对象不会执行真实的网络请求逻辑。

内容的提问来源于stack exchange,提问作者Fauziah -

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 18:01:24