0

我正在尝试为 Room Dao 编写 android 测试用例,我的返回类型是 Flow。我收到以下我无法理解的错误。为了测试流程,我使用了 Turbine 库,如果正确实施,它应该更容易处理这些情况。我需要您的帮助来了解问题以及处理问题的正确方法。什么是安全流量和不安全流量?

错误 :

    junit.framework.AssertionFailedError: expected:<kotlinx.coroutines.flow.FlowKt__BuildersKt$flowOf$$inlined$unsafeFlow$2@b649c74> but was:<kotlinx.coroutines.flow.SafeFlow@73a259d>
at junit.framework.Assert.fail(Assert.java:50)
at junit.framework.Assert.failNotEquals(Assert.java:287)
at junit.framework.Assert.assertEquals(Assert.java:67)
at junit.framework.Assert.assertEquals(Assert.java:74)
at com.swapnil.movieapp.model.persistence.MovieDaoTest$insertMovieDetails$1$1.invokeSuspend(MovieDaoTest.kt:67)
at com.swapnil.movieapp.model.persistence.MovieDaoTest$insertMovieDetails$1$1.invoke(Unknown Source:8)
at com.swapnil.movieapp.model.persistence.MovieDaoTest$insertMovieDetails$1$1.invoke(Unknown Source:4)
at app.cash.turbine.FlowTurbineKt$test$2.invokeSuspend(FlowTurbine.kt:86)
at app.cash.turbine.FlowTurbineKt$test$2.invoke(Unknown Source:8)
at app.cash.turbine.FlowTurbineKt$test$2.invoke(Unknown Source:4)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)
at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:264)
at app.cash.turbine.FlowTurbineKt.test(FlowTurbine.kt:55)
at app.cash.turbine.FlowTurbineKt.test$default(FlowTurbine.kt:51)
at com.swapnil.movieapp.model.persistence.MovieDaoTest$insertMovieDetails$1.invokeSuspend(MovieDaoTest.kt:66)
at com.swapnil.movieapp.model.persistence.MovieDaoTest$insertMovieDetails$1.invoke(Unknown Source:8)
at com.swapnil.movieapp.model.persistence.MovieDaoTest$insertMovieDetails$1.invoke(Unknown Source:4)
at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt$runTestCoroutine$2.invokeSuspend(TestBuilders.kt:208)
at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt$runTestCoroutine$2.invoke(Unknown Source:8)
at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt$runTestCoroutine$2.invoke(Unknown Source:4)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:55)
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:112)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTestCoroutine(TestBuilders.kt:207)
at kotlinx.coroutines.test.TestBuildersKt.runTestCoroutine(Unknown Source:1)
at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt$runTest$1$1.invokeSuspend(TestBuilders.kt:167)
at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt$runTest$1$1.invoke(Unknown Source:8)
at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt$runTest$1$1.invoke(Unknown Source:2)
at kotlinx.coroutines.test.TestBuildersJvmKt$createTestResult$1.invokeSuspend(TestBuildersJvm.kt:13)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source:1)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source:1)
at kotlinx.coroutines.test.TestBuildersJvmKt.createTestResult(TestBuildersJvm.kt:12)
at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest(TestBuilders.kt:166)
at kotlinx.coroutines.test.TestBuildersKt.runTest(Unknown Source:1)
at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest(TestBuilders.kt:154)
at kotlinx.coroutines.test.TestBuildersKt.runTest(Unknown Source:1)
at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest$default(TestBuilders.kt:147)
at kotlinx.coroutines.test.TestBuildersKt.runTest$default(Unknown Source:1)
at com.swapnil.movieapp.model.persistence.MovieDaoTest.insertMovieDetails(MovieDaoTest.kt:62)

DaoTest 类:

@ExperimentalCoroutinesApi
@RunWith(AndroidJUnit4::class)
@SmallTest
class MovieDaoTest {

    @get:Rule
    var instantTaskExecutorRule = InstantTaskExecutorRule()
    private lateinit var mockDatabase: MovieDatabase
    private lateinit var mockDao: MovieDao

    @Before
    fun setup(){
        mockDatabase = Room.inMemoryDatabaseBuilder(
            ApplicationProvider.getApplicationContext(),
            MovieDatabase::class.java)
            .allowMainThreadQueries()
            .build()

        mockDao = mockDatabase.movieDao()
    }

    @After
    fun tearDown(){
        mockDatabase.close()
    }

    @Test
    fun insertMovies() = runTest{
        val mockMovieEntity = MovieEntity(1, "/asda.jpg","eng","testMovie","testOverview", 8.0,"/nvkjasd.jpg","08-09-2021","testTitle",false,7.0,50)
        val mockMovieList : List<MovieEntity> = mutableListOf(mockMovieEntity,mockMovieEntity,mockMovieEntity,mockMovieEntity,mockMovieEntity,mockMovieEntity)
        mockDao.insertMovies(mockMovieList)
        val flowRes = listOf(mockMovieList).asFlow()
        flowOf(mockDao.getAllMovies()).test {
            assertEquals(flowRes,awaitItem())
            awaitComplete()
        }
    }

    @Test
    fun insertMovieDetails() = runTest{
        val movieDetails = MovieDetailEntity(1, "testTitle","testOverview","/asda.jpg","08-09-2021")
        mockDao.insertMovieDetails(movieDetails)
        val flowRes = flowOf(movieDetails)
        flowOf(mockDao.getMovieDetails(1)).test {
            assertEquals(flowRes,awaitItem())
            awaitComplete()
        }
    }

}

终于道课了

@Dao
interface MovieDao {

    @Query("SELECT * FROM MoviesDb")
    fun getAllMovies(): Flow<List<MovieEntity>>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertMovies(movies: List<MovieEntity>)

    @Query("DELETE FROM MoviesDb")
    suspend fun deleteAllMovies()

    @Query("SELECT * FROM MovieDetailsDb WHERE movieDetailId = :movieId")
    fun getMovieDetails(movieId: Int) : Flow<MovieDetailEntity>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertMovieDetails(detail: MovieDetailEntity)

}
4

0 回答 0