Android Kotlin用MockK Mock FirebaseAuth.getInstance()遇异常的解决方法
问题
在使用Kotlin和MockK为Android项目的ProfileScreenViewModel编写单元测试时,遇到MockKException: Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock异常。
ViewModel中通过静态方法初始化user属性:
// Inside ProfileScreenViewModel private val user = FirebaseAuth.getInstance().currentUser
测试初始化代码如下:
// Inside ProfileScreenViewModelTest @Before fun setUp() { // Mock FirebaseAuth val mockFirebaseAuth = mockk<FirebaseAuth>() val mockFirebaseUser = mockk<FirebaseUser>() every { mockFirebaseAuth.currentUser } returns mockFirebaseUser every { FirebaseAuth.getInstance() } returns mockFirebaseAuth // Mock other dependencies mockRepository = mockk() mockTimeProvider = mockk() // Initialize ViewModel with mocks viewModel = ProfileScreenViewModel(mockRepository, mockTimeProvider) }
期望FirebaseAuth.getInstance().currentUser返回模拟的FirebaseUser,但在every { FirebaseAuth.getInstance() } returns mockFirebaseAuth行抛出异常。尝试仅模拟currentUser时,ViewModel的user属性为null,且不想通过构造函数传入user。
解决方案
问题核心在于FirebaseAuth.getInstance()是静态方法,MockK默认仅支持模拟实例对象,要拦截静态方法调用,需使用mockkStatic工具处理:
- 在测试初始化方法中,先模拟
FirebaseAuth类的静态行为:
@Before fun setUp() { // 第一步:模拟FirebaseAuth的静态方法 mockkStatic(FirebaseAuth::class) val mockFirebaseAuth = mockk<FirebaseAuth>() val mockFirebaseUser = mockk<FirebaseUser>() // 第二步:配置静态方法返回模拟的FirebaseAuth实例 every { FirebaseAuth.getInstance() } returns mockFirebaseAuth // 第三步:配置模拟实例的currentUser返回预设的模拟用户 every { mockFirebaseAuth.currentUser } returns mockFirebaseUser // Mock其他依赖 mockRepository = mockk() mockTimeProvider = mockk() // 初始化ViewModel viewModel = ProfileScreenViewModel(mockRepository, mockTimeProvider) }
- (可选)为避免静态模拟污染其他测试,在测试结束后清理静态模拟:
@After fun tearDown() { unmockkStatic(FirebaseAuth::class) }
关键注意事项:
- 必须先调用
mockkStatic(FirebaseAuth::class),才能对FirebaseAuth.getInstance()这类静态方法使用every { ... }配置返回逻辑 - 静态模拟是全局生效的,测试完成后执行
unmockkStatic可以保证测试用例之间的独立性
内容的提问来源于stack exchange,提问作者Thimphou
相关产品推荐
相关产品推荐

