我正在尝试为 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)
}