如何在Android Hilt环境下断开与Firebase模拟器的连接
问题分析
Firebase Auth 和 Firestore 是全局单例对象,测试中调用 useEmulator 修改了单例的配置后,开发环境运行时会复用这个已被修改的单例,导致连接到模拟器而非生产 Firebase 服务。
解决方案
方案1:测试使用独立 FirebaseApp 实例(推荐)
创建测试专用的 FirebaseApp 实例,与开发环境的默认实例完全隔离,避免配置互相影响。
修改测试模块的 FakeFirebaseModule:
@Module @TestInstallIn(components = [SingletonComponent::class], replaces = [FirebaseModule::class]) object FakeFirebaseModule { private val TAG = FakeFirebaseModule::class.simpleName private const val TEST_APP_NAME = "TestFirebaseApp" @Singleton @Provides fun provideTestFirebaseApp(context: Context): FirebaseApp { // 复用已存在的测试实例,否则创建新实例 return try { FirebaseApp.getInstance(TEST_APP_NAME) } catch (e: IllegalStateException) { val options = FirebaseOptions.fromResource(context) FirebaseApp.initializeApp(context, options, TEST_APP_NAME) } } @Singleton @Provides fun provideAuth(app: FirebaseApp): FirebaseAuth = FirebaseAuth.getInstance(app).apply { try { useEmulator("10.0.2.2", 9099) } catch (e: IllegalStateException) { Log.e(TAG, "User emulator failed", e) } } @Singleton @Provides fun provideDb(app: FirebaseApp): FirebaseFirestore = FirebaseFirestore.getInstance(app).apply { try { useEmulator("10.0.2.2", 8080) } catch (e: IllegalStateException) { Log.e(TAG, "User emulator failed", e) } firestoreSettings = FirebaseFirestoreSettings.Builder().setPersistenceEnabled(false).build() } }
测试使用独立的 TestFirebaseApp 实例,开发环境继续使用默认 Firebase 实例,两者配置完全独立。
方案2:开发模块强制重置配置
在开发环境的 FirebaseModule 中,强制恢复 Firebase 实例到生产环境配置,覆盖测试留下的模拟器设置。
修改开发模块的 FirebaseModule:
@Module @InstallIn(SingletonComponent::class) object FirebaseModule { @Singleton @Provides fun provideAuth(): FirebaseAuth = Firebase.auth.apply { // 通过反射重置 Auth 模拟器配置(依赖 Firebase 内部实现,版本更新可能失效) try { val emulatorSettingsField = FirebaseAuth::class.java.getDeclaredField("emulatorSettings") emulatorSettingsField.isAccessible = true emulatorSettingsField.set(this, null) } catch (e: Exception) { // 反射失败时忽略,默认使用生产环境 } } @Singleton @Provides fun provideDb(): FirebaseFirestore = Firebase.firestore.apply { // 重新设置 Firestore 配置,清除模拟器设置 firestoreSettings = FirebaseFirestoreSettings.Builder().build() // 开发环境自定义设置可在此添加 } }
方案3:测试后清理配置
在测试的 @After 方法中重置 Firebase 实例配置,降低开发环境被影响的概率。
修改测试代码:
@UninstallModules(FirebaseModule::class) @HiltAndroidTest @MediumTest class ExampleTest { private val TAG = ExampleTest::class.simpleName // ... 现有代码 ... @After fun tearDown() { // 重置 Auth 模拟器配置 try { val emulatorSettingsField = FirebaseAuth::class.java.getDeclaredField("emulatorSettings") emulatorSettingsField.isAccessible = true emulatorSettingsField.set(auth, null) } catch (e: Exception) { Log.e(TAG, "Failed to reset Auth emulator config", e) } // 重置 Firestore 模拟器配置 db.firestoreSettings = FirebaseFirestoreSettings.Builder().build() } }
注:若测试崩溃或未正常执行 @After,配置仍可能残留,可靠性不如方案1。
内容的提问来源于stack exchange,提问作者Eva
相关产品推荐
相关产品推荐

