如何用JUnit和MockK测试Kotlin中init块调用的私有函数
测试ViewModel初始化块中调用的私有函数(JUnit + MockK)
首先明确:更推荐测试私有函数带来的行为结果,而非直接测试私有函数本身——毕竟私有函数是内部实现细节,测试行为能让你的测试更健壮,哪怕以后重构私有函数的逻辑或名字,只要对外行为不变,测试就不会失效。但如果确实需要验证它被调用,或者测试其内部逻辑,用MockK可以做到。
场景1:验证doSomething()在初始化时被调用
用MockK的spyk创建ViewModel的 spy 实例,它能保留原对象的行为,同时记录函数调用,再结合私有函数验证语法即可:
import io.mockk.mockk import io.mockk.spyk import io.mockk.verify import org.junit.Test class ViewModelTest { @Test fun `viewModel初始化时会调用doSomething私有函数`() { // Mock Repository依赖 val mockRepo = mockk<Repository>(relaxed = true) // 创建ViewModel的spy实例,开启私有调用记录 val viewModel = spyk(ViewModel(mockRepo), recordPrivateCalls = true) // 验证私有函数doSomething被调用了一次 verify(exactly = 1) { viewModel["doSomething"]() } } }
场景2:测试doSomething()的内部逻辑
如果doSomething()里是调用Repository的方法,那直接测试Repository的方法是否被正确调用就行,完全不用管私有函数:
import io.mockk.coVerify import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Before import org.junit.Test class ViewModelTest { @Before fun setup() { // 替换主线程为测试调度器,避免viewModelScope协程在测试中挂起 Dispatchers.setMain(UnconfinedTestDispatcher()) } @After fun teardown() { Dispatchers.resetMain() } @Test fun `doSomething会正确调用Repository的目标方法`() { // Mock Repository,预设方法行为 val mockRepo = mockk<Repository>() coEvery { mockRepo.someMethod() } returns Unit // 初始化ViewModel,触发init块和doSomething ViewModel(mockRepo) // 验证Repository的挂起方法被调用了一次 coVerify(exactly = 1) { mockRepo.someMethod() } } }
补充说明
- 尽量用场景2的方式测试,它属于黑盒测试,不耦合内部实现,维护成本更低。
- 场景1的方式耦合了私有函数的名字,以后如果重构改名,测试就得跟着改,除非你确实需要确保这个私有函数被执行,否则不推荐。
内容的提问来源于stack exchange,提问作者Kleini
相关产品推荐
相关产品推荐

