我尝试对Android Room Database进行单元测试。
我遇到这样的错误:Method getMainLooper in android.os.Looper not mocked
试图通过RxAndroid概念实现。
A)然后我应用了'How to unit test your RxJava code in Kotlin'的样本,一切都很好。
B)接下来,我只是将Room instance
插入到此工作示例中,再次出现错误!
代码如下:
class MoviesResponse2(val page: Int,
val total_results: Int,
val total_pages: Int,
val results: List<MovieResponse2>)
data class Movie2(val title: String, val text: String, val _image: String) {
val image: String
get() = "http://www.base.url/$_image"
}
val db = Room.databaseBuilder(MockContext(), MovieResponseDatabase::class.java, "mresp_db").build()
class MoviesClient2 {
fun fetchMovies(): Maybe<MoviesResponse2> {
return db.mySubjDao().get("").flatMap {
Maybe.just(MoviesResponse2(0,0,0, listOf(it)))
}
}
}
class MoviesInteractor2(val client2: MoviesClient2) {
fun requestTopMovies(): Maybe<List<Movie2>> {
return client2.fetchMovies()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map {
it.results.map {
Movie2(it.title, it.overview, it.backdrop_path)
}
}
}
}
@Entity(tableName = "tbl_my_movies")
data class MovieResponse2 (
@PrimaryKey(autoGenerate = true)
val id: Long = 0,
@ColumnInfo(name = "title")
var title: String,
@ColumnInfo(name = "backdrop_path")
val backdrop_path: String,
@ColumnInfo(name = "overview")
val overview: String
) {
@Ignore
constructor(title: String, overview: String, backdrop_path: String) : this(0, title, overview, backdrop_path)
}
@Dao
interface MyMovieDao {
@Query("SELECT * FROM tbl_my_movies")
fun getAll(): Maybe<MovieResponse2>
@Query("SELECT * FROM tbl_my_movies WHERE title = :title")
fun get(title: String): Maybe<MovieResponse2>
@Insert
fun insert(mySubj: MovieResponse2)
}
@Database(
entities = [MovieResponse2::class],
version = 1)
abstract class MovieResponseDatabase : RoomDatabase() {
abstract fun mySubjDao(): MyMovieDao
}
class MoviesInteractor2Test {
@Rule
@JvmField
var testSchedulerRule = RxImmediateSchedulerRule2()
lateinit var client2: MoviesClient2
internal lateinit var underTest: MoviesInteractor2
internal lateinit var ctx: MockContext
@Before
fun setUp() {
client2 = MoviesClient2()
underTest = MoviesInteractor2(client2)
ctx = MockContext()
db.mySubjDao().insert(MovieResponse2("title1", "overview1", "/backdrop1"))
}
@Test
fun `when 2 top movies are requested, should call client and return response`() {
val result = underTest.requestTopMovies()
val testObserver = TestObserver<List<Movie2>>()
result.subscribe(testObserver)
testObserver.assertComplete()
testObserver.assertNoErrors()
testObserver.assertValueCount(1)
val listResult = testObserver.values()[0]
assertThat(listResult.size, `is`(1))
assertThat(listResult[0].title, `is`("b"))
assertThat(listResult[0].image, `is`("http://www.base.url/c"))
assertThat(listResult[0].text, `is`("d"))
}
}
class RxImmediateSchedulerRule2 : TestRule {
override fun apply(base: Statement, d: Description): Statement {
return object : Statement() {
@Throws(Throwable::class)
override fun evaluate() {
RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() }
RxJavaPlugins.setComputationSchedulerHandler { Schedulers.trampoline() }
RxJavaPlugins.setNewThreadSchedulerHandler { Schedulers.trampoline() }
RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() }
try {
base.evaluate()
} finally {
RxJavaPlugins.reset()
RxAndroidPlugins.reset()
}
}
}
}
}
除了某些Room Database
对象之外,此代码与上述代码等效。但是我又遇到了这个错误:
java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. See http://g.co/androidstudio/not-mocked for details.
at android.os.Looper.getMainLooper(Looper.java)
at android.arch.core.executor.DefaultTaskExecutor.isMainThread(DefaultTaskExecutor.java:58)
at android.arch.core.executor.ArchTaskExecutor.isMainThread(ArchTaskExecutor.java:116)
at android.arch.persistence.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:203)
at android.arch.persistence.room.RoomDatabase.beginTransaction(RoomDatabase.java:251)
at com.gdetotut.mn2019.MyMovieDao_Impl.insert(MyMovieDao_Impl.java:53)
at com.gdetotut.mn2019.MoviesInteractor2Test.setUp(test_db.kt:110)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at com.gdetotut.mn2019.RxImmediateSchedulerRule2$apply$1.evaluate(test_db.kt:142)
我被困住了。怎么了?