问题
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/Ali-Rezaei/TMDb-Paging
来源:https://stackoverflow.com/questions/60668360/unit-test-for-a-viewmodel-class-with-lazy-loading