Unit Test for a ViewModel class with lazy loading

2020-03-13T18:01:28

I am trying to write a unit test for my viewModel class which has lazy loading. I have following ViewModel class :

abstract class DetailViewModel(item: TmdbItem) : BaseViewModel() {

    private val _trailers = MutableLiveData<List<Video>>()
    val trailers: LiveData<List<Video>>
        get() = _trailers

    private val _cast: MutableLiveData<List<Cast>> by lazy {
        MutableLiveData<List<Cast>>().also {
            arrayOf(composeObservable { getTrailers(item.id) }
                    .subscribe({ videos ->
                        _trailers.postValue(videos)
                    }) { throwable -> Timber.e(throwable) }
                    , composeObservable { getCast(item.id) }
                    .subscribe({ cast ->
                        _cast.postValue(cast)
                    }) { throwable -> Timber.e(throwable) }).also { compositeDisposable.addAll(*it) }
        }
    }
    val cast: LiveData<List<Cast>>
        get() = _cast

    protected abstract fun getTrailers(id: Int): Observable<List<Video>>

    protected abstract fun getCast(id: Int): Observable<List<Cast>>
}

I wrote a unit test for it as follow:

RunWith(MockitoJUnitRunner::class)
class DetailViewModelTest {

    @get:Rule
    var rule: TestRule = InstantTaskExecutorRule()

    @Mock
    private lateinit var api: TmdbApi

    @Test
    fun loadTrailersAndCast() {
        val observableResponseVideo = Observable.just(TmdbApi.VideoWrapper(
                listOf(Video("id", "name", "site", "key", 20, "type"))))
        `when`(api.movieTrailers(1)).thenReturn(observableResponseVideo)

        val observableResponseCast = Observable.just(TmdbApi.CastWrapper(
                listOf(Cast("char", "name", null, 1))))
        `when`(api.movieCast(1)).thenReturn(observableResponseCast)

        val viewModel = MovieDetailViewModel(api, Movie(1, "overview", "2012", null,
                null, "title", 9.0))

        val observer = LoggingObserver<List<Cast>>()
        viewModel.cast.observeForever(observer)

        val observer2 = LoggingObserver<List<Video>>()
        viewModel.trailers.observeForever(observer2)

        with(observer.value) {
            assertThat(this, `is`(notNullValue()))
            assertTrue(this!!.isNotEmpty())
            assertThat(this.size, `is`(1))
        }

        with(observer2.value) {
            assertThat(this, `is`(notNullValue()))
            assertTrue(this!!.isNotEmpty())
            assertThat(this.size, `is`(1))
        }
    }

    /**
     * simple observer that logs the latest value it receives
     */
    private class LoggingObserver<T> : Observer<T> {
        var value: T? = null
        override fun onChanged(t: T?) {
            this.value = t
        }
    }
}

I receive following error when I execute the test:

*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844



java.lang.StackOverflowError
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:411)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at io.reactivex.Observable.subscribe(Observable.java:12034)
    at io.reactivex.Observable.subscribe(Observable.java:12016)
    at io.reactivex.Observable.subscribe(Observable.java:11945)
    at com.sample.android.tmdb.ui.detail.DetailViewModel$_cast$2.invoke(DetailViewModel.kt:25)
    at com.sample.android.tmdb.ui.detail.DetailViewModel$_cast$2.invoke(DetailViewModel.kt:12)
    at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
    at com.sample.android.tmdb.ui.detail.DetailViewModel.get_cast(DetailViewModel.kt)
    at com.sample.android.tmdb.ui.detail.DetailViewModel.access$get_cast$p(DetailViewModel.kt:12)
    at com.sample.android.tmdb.ui.detail.DetailViewModel$_cast$2$$special$$inlined$also$lambda$4.accept(DetailViewModel.kt:26)
    at com.sample.android.tmdb.ui.detail.DetailViewModel$_cast$2$$special$$inlined$also$lambda$4.accept(DetailViewModel.kt:12)

Do you know how can I resolve the error?

You can find full source code at : https://github.com/AliRezaeiii/TMDb-Paging

Copyright License:
Author:「Ali」,Reproduced under the CC 4.0 BY-SA copyright license with link to original source & disclaimer.
Link to:https://stackoverflow.com/questions/60668360/unit-test-for-a-viewmodel-class-with-lazy-loading

About “Unit Test for a ViewModel class with lazy loading” questions

I am trying to write a unit test for my viewModel class which has lazy loading. I have following ViewModel class : abstract class DetailViewModel(item: TmdbItem) : BaseViewModel() { private val
We have following code for ViewModel : class MyViewModel : ViewModel() { private val users: MutableLiveData&lt;List&lt;User&gt;&gt; by lazy { MutableLiveData().also { loadUs...
I have used the lazy loading of images solution from Ben Nadel's blog: http://www.bennadel.com/blog/2498-lazy-loading-image-with-angularjs.htm and modified it slightly to work as we want. No proble...
I am trying to write unit test for my ViewModel class. In this case, I have an activity that when created, it subscribes to my repo (LiveData from viewModel) and retrieves a list of Github reposito...
I have a viewmodel that only emits the value of repo when I subscribe to it in the activity. I am trying to unit test the viewmodel (see code below) but I am getting NPE because repo is null. How c...
How to write the unit test cases for lazy loading in angular 8. i tried a lot but my unit test cases are not covering "loadChildren" routing. import { Routes, RouterModule } from "@angular/router";
Consider the following code: sealed interface State { object Loading : State data class Content(val someString: String) : State } class SomeViewModel(getSomeStringUseCase: GetSomeStringUse...
I have an TabControl which displays a collection of my ViewModels. The mapping between ViewModel and View is implemented by DataTemplate. I use MVVM but without PRISM (for historical reasons). The
I'm trying to write a unit test for my viewModel and I haven't figure out how to do it. I am using kotlin flow and jetpack compose. In the viewModel, the function changes de value of a mutableState...
I am unit testing my viewmodel and I always keep getting NullPointerException. Here is my viewmodel code - class LoginViewModel(private val myUseCase: MyUseCase) :BaseViewModel() { private val

Copyright License:Reproduced under the CC 4.0 BY-SA copyright license with link to original source & disclaimer.