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

Kotlin单元测试遇Mockito无法mock final类DataRepository问题求助

问题排查与解决方案

错误原因

  • 原因1:Kotlin类默认被final修饰,Mockito核心库默认不支持mock/spy final类,直接触发你遇到的报错。
  • 原因2:测试代码中错误将MainActivityViewModel标记为@Mock,你需要测试ViewModel的真实逻辑,mock后的ViewModel不会执行真实的getCreditReport方法,自然无法触发Repository调用。
  • 原因3(潜在问题):ViewModel中使用了Dispatchers.IO调度器,单元测试环境没有Android主线程调度器,不做处理会触发运行时异常。

修复步骤

步骤1:解决final类无法mock的问题,三选一即可

  • 方案1(最便捷):引入mockito-inline依赖,该组件支持mock final类,在Module级build.gradle的test依赖中添加:
testImplementation 'org.mockito:mockito-inline:4.11.0'
  • 方案2:修改DataRepository类为open类型,解除final限制:
open class DataRepository @Inject constructor(
    private val retroServiceInterface: RetroServiceInterface
) {
    // 方法如果需要单独mock也可以加open修饰
    open suspend fun getCreditReport(): CreditReport {
        return retroServiceInterface.getDataFromApi()
    }
}
  • 方案3(架构更规范):抽象Repository接口,测试时mock接口(接口默认非final):
interface DataRepositoryInterface {
    suspend fun getCreditReport(): CreditReport
}

class DataRepository @Inject constructor(
    private val retroServiceInterface: RetroServiceInterface
) : DataRepositoryInterface {
    override suspend fun getCreditReport(): CreditReport {
        return retroServiceInterface.getDataFromApi()
    }
}
// ViewModel构造参数改为接口类型
class MainActivityViewModel @Inject constructor(
    private val dataRepository: DataRepositoryInterface
) : ViewModel()

步骤2:修正单元测试代码

首先引入协程测试依赖,处理ViewModel中的协程调度问题:

testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3"

修正后的测试代码:

@RunWith(MockitoJUnitRunner::class)
class MainActivityViewModelTest {
    @Mock
    private lateinit var dataRepository: DataRepository
    private lateinit var mainActivityViewModel: MainActivityViewModel

    @Before
    fun setup() {
        // 替换主线程调度器为测试调度器
        Dispatchers.setMain(StandardTestDispatcher())
        // 手动实例化真实ViewModel,传入mock的Repository
        mainActivityViewModel = MainActivityViewModel(dataRepository)
    }

    @After
    fun tearDown() {
        // 测试完成重置调度器
        Dispatchers.resetMain()
    }

    @Test
    fun `getCreditReport调用时触发Repository对应方法`() = runTest {
        // 调用待测方法
        mainActivityViewModel.getCreditReport()
        // 等待所有协程任务执行完成
        advanceUntilIdle()
        // 验证Repository方法被调用
        verify(dataRepository).getCreditReport()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 12:21:01