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

无法对含Firebase代码的仓库执行单元测试,报错无instrumentation注册

解决本地单元测试中Firebase初始化的Instrumentation异常

问题根源

  1. 本地单元测试无Instrumentation环境:你的测试放在test包(本地单元测试),这类测试运行在电脑JVM上,没有Android系统的Instrumentation支持,调用InstrumentationRegistry.getInstrumentation()必然抛出No instrumentation registered异常。
  2. Firebase实例未依赖注入:仓库里直接用Firebase.auth、Firebase.firestore静态方法获取实例,你mock的FirebaseAuth和FirebaseFirestore根本没被仓库用到,白做了mock。

修复步骤

1. 修改仓库,通过构造函数注入Firebase实例

把FirebaseAuth和FirebaseFirestore作为构造参数传入仓库,替换静态调用:

class HelpRepositoryImpl @Inject constructor(
    @IoDispatcher private val dispatcher: CoroutineDispatcher,
    private val firebaseAuth: FirebaseAuth, // 注入FirebaseAuth实例
    private val firebaseFirestore: FirebaseFirestore // 注入FirebaseFirestore实例
) : HelpRepository {

    override suspend fun sendSuggestionMessage(message: String): Result<Unit> {
        return withContext(dispatcher) {
            try {
                val userMail = firebaseAuth.currentUser?.email ?: "no-email" // 使用注入的实例
                firebaseFirestore.collection("messages") // 使用注入的实例
                    .add(SuggestionMessage(message, userMail))
                    .await()
                Result.success(Unit)
            } catch (e: Exception) {
                Result.failure(e)
            }
        }
    }
}

2. 修改测试代码,移除Instrumentation相关逻辑

本地单元测试不需要初始化FirebaseApp,直接把mock的实例传给仓库即可:

@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(MockitoJUnitRunner::class)
class HelpRepositoryImplTest {

    private lateinit var helpRepository: HelpRepository

    @Mock
    private lateinit var firebaseAuth: FirebaseAuth

    @Mock
    private lateinit var firebaseFirestore: FirebaseFirestore

    @Mock
    private lateinit var firebaseUser: FirebaseUser

    @Mock
    private lateinit var collectionReference: CollectionReference

    private val testDispatcher = UnconfinedTestDispatcher()

    @Before
    fun setup() {
        MockitoAnnotations.openMocks(this)
        // 移除FirebaseApp初始化和Instrumentation相关代码
        // 把mock实例传入仓库构造函数
        helpRepository = HelpRepositoryImpl(
            dispatcher = testDispatcher,
            firebaseAuth = firebaseAuth,
            firebaseFirestore = firebaseFirestore
        )
    }

    @Test
    fun send_message_test() = runBlocking {
        val message = "Test message"
        val userMail = "test9@firebase.com"
        val documentReference = mock<DocumentReference>()
        val task: Task<DocumentReference> = Tasks.forResult(documentReference)

        whenever(firebaseAuth.currentUser).thenReturn(firebaseUser)
        whenever(firebaseUser.email).thenReturn(userMail)
        whenever(firebaseFirestore.collection(any())).thenReturn(collectionReference)
        whenever(collectionReference.add(SuggestionMessage(message, userMail))).thenReturn(task)

        val messageResult = helpRepository.sendSuggestionMessage(message)
        assertTrue(task.isSuccessful)
        assertTrue(messageResult.isSuccess)
        assertEquals(Unit, messageResult.getOrNull())
    }
}

额外说明

如果你的项目用了Hilt依赖注入,在测试中可以配合Hilt测试规则简化mock注入,但上面的修改已经能解决核心问题:让mock真正生效,同时避开Instrumentation的环境限制。

内容的提问来源于stack exchange,提问作者Gastón Saillán

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 08:28:10