无法对含Firebase代码的仓库执行单元测试,报错无instrumentation注册
解决本地单元测试中Firebase初始化的Instrumentation异常
问题根源
- 本地单元测试无Instrumentation环境:你的测试放在
test包(本地单元测试),这类测试运行在电脑JVM上,没有Android系统的Instrumentation支持,调用InstrumentationRegistry.getInstrumentation()必然抛出No instrumentation registered异常。 - 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
相关产品推荐
相关产品推荐

