簡體   English   中英

如何使用 Android Hilt 從 Firebase 仿真器斷開連接

[英]How to disconnect from Firebase emulator using Android Hilt

我正在嘗試使用 Firebase Auth 和 Firestore 模擬器進行測試,但我真正的 Firebase 應用程序進行開發。 我有用於依賴注入的 Hilt。 在我的測試模塊中,我設置useEmulator但在我的開發模塊中,我只使用了 Firebase 單例。 事實證明,開發仍在使用模擬器,因為 singleton 在測試和開發之間共享。 如何在開發模塊中斷開與模擬器的連接?

開發模塊:

@Module
@InstallIn(SingletonComponent::class)
object FirebaseModule {
    @Singleton
    @Provides
    fun provideAuth(): FirebaseAuth = Firebase.auth

    @Singleton
    @Provides
    fun provideDb(): FirebaseFirestore = Firebase.firestore
}

測試模塊:

@Module
@TestInstallIn(components = [SingletonComponent::class], replaces = [FirebaseModule::class])
object FakeFirebaseModule {
    private val TAG = FakeFirebaseModule::class.simpleName

    @Singleton
    @Provides
    fun provideAuth(): FirebaseAuth = Firebase.auth.apply {
        try {
            useEmulator("10.0.2.2", 9099)
        } catch (e: IllegalStateException) {
            Log.e(TAG, "User emulator failed", e)
        }
    }

    @Singleton
    @Provides
    fun provideDb(): FirebaseFirestore = Firebase.firestore.apply {
        try {
            useEmulator("10.0.2.2", 8080)
        } catch (e: IllegalStateException) {
            Log.e(TAG, "User emulator failed", e)
        }
        firestoreSettings = FirebaseFirestoreSettings.Builder().setPersistenceEnabled(false).build()
    }
}

測試:

@UninstallModules(FirebaseModule::class)
@HiltAndroidTest
@MediumTest
class ExampleTest {
    private val hiltRule = HiltAndroidRule(this)

    private val composeTestRule = createAndroidComposeRule<MainActivity>()

    @get:Rule
    val rule: TestRule = RuleChain.outerRule(hiltRule).around(composeTestRule)

    @Inject
    lateinit var auth: FirebaseAuth

    @Inject
    lateinit var db: FirebaseFirestore

    @Before
    fun setUp() {
        hiltRule.inject()
        auth.createUserWithEmailAndPassword(TestData.UserEmail1, TestData.UserPassword1)
            .addOnFailureListener {
                auth.signInWithEmailAndPassword(TestData.UserEmail1, TestData.UserPassword1)
            }
    }

    // ...
}

模擬器(Firestore)似乎沒有斷開連接功能,並且連接時這些字段是私有的。 請參閱此鏈接

在這種情況下,刪除 @Singleton 以獲取不同的 Firestore 實例,或將 singleton 范圍限定為不同的(測試與生產)環境將使生產 Firestore 無法連接到模擬器。

*嘆氣*我發現出了什么問題,我完全看錯了地方。 我以為我的開發代碼使用的是測試數據,但實際上它使用的是陳舊的開發數據。 我的代碼中有這個:

inline fun <reified T : Any> Query.getObjectsFlow() = callbackFlow {
    val subscription = addSnapshotListener { value, error ->
        when {
            error != null -> cancel("Get snapshot failed", error)
            value != null -> trySend(value.toObjects<T>())
        }
    }

    awaitClose { subscription.remove() }
}

像這樣使用:

// Repository

val feed = db.collection(FEED_COLLECTION)
            .getObjectsFlow<FeedItemDocument>()
            .map { docs ->
                val feedItems = docs.map { FeedItemState.fromDocument(it) }
                if (feedItems.isEmpty()) {
                    LoadState.Empty()
                } else {
                    LoadState.Data(Feed(feedItems))
                }
            }
            .catch {
                Log.e(TAG, "Error querying server", it)
                emit(LoadState.Failure(it))
            }

// FeedItemState

data class FeedItemState(
    val id: String = "",
    val createdAt: Instant = Instant.now(),
    val text: String = "",
) {
    companion object {
        fun fromDocument(doc: FeedItemDocument): FeedItemState {
            val id = doc.id!!
            val createdAt = doc.createdAt?.toDate()?.toInstant()!!
            val text = doc.text!!
            return FeedItemState(type, id, createdAt, text)
        }
    }
}

如果任何文檔字段為 null,我的存儲庫將發出加載失敗值。 但是,快照偵聽器會發出每個查詢 object 包括舊查詢。 這意味着當我將字段添加到數據庫時,發出的第一個 object 不會有新字段,因此會拋出 NPE。

我不得不更改存儲庫以接受並忽略 null 字段。 因此fromDocument mapNotNull字段為docs.map { FeedItemState.fromDocument(it) }而不是使用!! .

經驗教訓:如果您使用的是 Kotlin !! ,對代碼非常懷疑。 它通常可以用不會拋出 NPE 的東西代替。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM