[英]How to connect Firebase emulator in Swift by using typescript?
[英]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.