1

I try to make unit tests for Android Room Database. I got error like that: Method getMainLooper in android.os.Looper not mocked when tried to make it thru with RxAndroid concept.

A) Then i applied sample from 'How to unit test your RxJava code in Kotlin' and it all was good. B) Next i just inserted Room instance to this working sample and got error again!

Here is the code:

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()
                }
            }
        }
    }
}

This code is equivalent to that mentioned above except some Room Database objects. But i catched this error again:

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)

I am stucked. What's wrong?

  • maybe a the same problem as here, which would make it a duplicate https://stackoverflow.com/questions/45988310/setvalue-and-postvalue-on-mutablelivedata-in-unittest – findusl Jan 23 '19 at 11:38

0 Answers0