首页 > 解决方案 > Android Kotlin 测试:确保 firebase 实时数据库数据创建在仪器测试之前同步运行

问题描述

如何确保在androidTest运行之前将数据添加到 Firebase 实时数据库。

我使用 Firebase 模拟器运行测试并使用 Koin 进行依赖注入。初始设置如下所示:

@MediumTest
@RunWith(AndroidJUnit4::class)
class GratitudeDetailFragmentTest: AutoCloseKoinTest() {

    private lateinit var gratitudeRepository: GratitudeRepository
    private lateinit var appContext: Application
    private lateinit var firebaseAuth: FirebaseAuth
    private lateinit var firebaseDatabase: FirebaseDatabase
    private val email = "testuser@gmail.com"
    private val password = "x7yer3232!ss"


    @ExperimentalCoroutinesApi
    @Before
    fun init() {

        stopKoin()//stop the original app koin

        appContext = ApplicationProvider.getApplicationContext()
        firebaseDatabase = FirebaseDatabase.getInstance()
        firebaseDatabase.useEmulator("10.0.2.2", 9000)
        firebaseAuth = FirebaseAuth.getInstance()
        firebaseAuth.useEmulator("10.0.2.2", 9099)
        val myModule = module(override = true) {

            single { firebaseDatabase }
            single { firebaseAuth }
            single {
                GratitudeRepository.getInstance()
            }
           
        }

        // start Koin!
        startKoin {
            // declare used Android context
            androidContext(appContext)
            // declare modules
            modules(listOf(myModule))
        }

        //clear the data to start fresh
        runBlocking {
            // Clear all (the problem is that this fails with perm denied)
            // firebaseDatabase.reference.setValue(null)
            // Now Koin is started get the ref to repo
            gratitudeRepository = GratitudeRepository()
            // ensure we have a user created
            firebaseAuth.createUserWithEmailAndPassword(email, password)

            // ensure 1 task
            make_lists()

        }
    }

    @After
    fun stop() {
        stopKoin()
    }


    private fun make_lists() {
        firebaseAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener {
            Timber.d("current user id: ${firebaseAuth.currentUser!!.uid}")
            gratitudeListKey = firebaseDatabase.reference.child("gratitude_items").push().key!!
            Timber.d("gratitude key id: $gratitudeListKey")
            val gratitudeList = FirebaseGratitudeList(
                gratitudeListId = gratitudeListKey,
                userId = firebaseAuth.currentUser!!.uid,
                createdDate = System.currentTimeMillis(),
                gratitudeItems = null)
            firebaseDatabase.reference.child("gratitude_items")
                .child(gratitudeListKey).setValue(gratitudeList).addOnCompleteListener {
                    Timber.d("Created list")
                }
        }
        }

至于实际测试本身,我尝试了很多东西,例如

    @ExperimentalCoroutinesApi
    @Test
    fun newGratitudeList_displaysZeroItems() = runBlockingTest {
        

        //Thread.sleep(2000)

        val bundle = bundleOf("gratitudeListIdKey" to gratitudeListKey)
        launchFragmentInContainer<GratitudeDetailFragment>(
            bundle,
            R.style.Theme_Sossego
        )


    }

但这仅在线程睡眠未注释时才有效,并且似乎runBlocking不能保证@Before测试的部分终止。

只有另一方面,如果我将生成列表代码移动到测试主体并移动launchFragmentInContainer到 firebase 回调,那么我会收到一个关于无法在主循环器上运行的错误(显然它通常在 UI 线程上,我猜是 Firebase 回调是强迫它成为主要的调度员?)

    @ExperimentalCoroutinesApi
    @Test
    fun newGratitudeList_displaysZeroItems() = runBlockingTest {
        

        firebaseAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener {
            Timber.d("current user id: ${firebaseAuth.currentUser!!.uid}")
            gratitudeListKey = firebaseDatabase.reference.child("gratitude_items").push().key!!
            Timber.d("gratitude key id: $gratitudeListKey")
            val gratitudeList = FirebaseGratitudeList(
                gratitudeListId = gratitudeListKey,
                userId = firebaseAuth.currentUser!!.uid,
                createdDate = System.currentTimeMillis(),
                gratitudeItems = null)
            firebaseDatabase.reference.child("gratitude_items")
                .child(gratitudeListKey).setValue(gratitudeList).addOnCompleteListener {


                    // Still seems to try to run this on main and gives problems :(
                    runBlockingTest {
                        val bundle = bundleOf("gratitudeListIdKey" to gratitudeListKey)
                        launchFragmentInContainer<GratitudeDetailFragment>(
                            bundle,
                            R.style.Theme_Sossego
                        )
                    }

                }
        }


    }

在我的 android 测试之前,我可以通过什么方式确保 firebase 数据 100% 完成,这样它们就不会不稳定?

标签: androidfirebaseunit-testingkotlin

解决方案


推荐阅读