【问题标题】:Testing a RxJava call with Retrofit in MVP get Wanted but not invoked在 MVP 中使用 Retrofit 测试 RxJava 调用被通缉但未被调用
【发布时间】:2020-02-19 10:15:15
【问题描述】:

我正在尝试使用改造和 rxJava 测试我的服务器调用。我在 koin 中使用 MVP 模式,当我尝试测试执行调用以从服务器获取数据的方法时遇到了一些问题。

我有一个调用交互器来检索数据的演示器。 Interactor DI 是用 koin 完成的。

我在这里和谷歌做了一些研究,我一直在看的所有例子都不适合我。

我遇到的错误是这样的:

Wanted but not invoked:
callback.onResponseSearchFilm(
    [Film(uid=1, id=1724, title=The incredible Hulk, tagline=You'll like him when he's angry., overview=Scientist Bruce Banner scours the planet for an antidote to the unbridled force of rage within..., popularity=22.619048, rating=6.1, ratingCount=4283, runtime=114, releaseDate=2008-06-12, revenue=163712074, budget=150000000, posterPath=/bleR2qj9UluYl7x0Js7VXuLhV3s.jpg, originalLanguage=en, genres=null, cast=null, poster=null, favourite=false), Film(uid=2, id=1724, title=The incredible Hulk, tagline=You'll like him when he's angry., overview=Scientist Bruce Banner scours the planet for an antidote to the unbridled force of rage within..., popularity=22.619048, rating=8.0, ratingCount=4283, runtime=114, releaseDate=2008-06-12, revenue=163712074, budget=150000000, posterPath=/bleR2qj9UluYl7x0Js7VXuLhV3s.jpg, originalLanguage=en, genres=null, cast=null, poster=null, favourite=false), Film(uid=3, id=1724, title=The incredible Hulk, tagline=You'll like him when he's angry., overview=Scientist Bruce Banner scours the planet for an antidote to the unbridled force of rage within..., popularity=22.619048, rating=8.5, ratingCount=4283, runtime=114, releaseDate=2008-06-12, revenue=163712074, budget=150000000, posterPath=/bleR2qj9UluYl7x0Js7VXuLhV3s.jpg, originalLanguage=en, genres=null, cast=null, poster=null, favourite=false)]
);
-> at com.filmfy.SearchImplTest.loadItems_WhenDataIsAvailable(SearchImplTest.kt:30)
Actually, there were zero interactions with this mock.

这是我的测试

class SearchImplTest: KoinTest {

    private val searchImpl: SearchImpl = mock()
    private val callback: SearchContract.Callback? = mock()
    private val api: RetrofitAdapter = mock()


    @Test
    fun loadItems_WhenDataIsAvailable() {
        `when`(api.getFilms()).thenReturn(Observable.just(filmRequestFacke()))
        searchImpl.getfilms(callback)
        verify(callback)?.onResponseSearchFilm(fackeFilms())
    }
}

我的交互代码:

class SearchImpl : AbstractInteractor() {

    private val voucherApiServe by lazy {
        RetrofitAdapter.create()
    }

    fun getfilms(callback: SearchContract.Callback?){
        disposable = voucherApiServe.getFilms()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                { result -> processFilmSearch(result.data, callback)},
                { error -> processError(error) }
            )
    }

fun processFilmSearch(filmList : ArrayList<Film>?, callback: SearchContract.Callback?){
        callback?.onResponseSearchFilm(filmList)
    }
.
.
.

我的 koin 模块:

factory<SearchContract.Presenter> { (view: SearchContract.View) -> SearchPresenter(view, mSearchImpl = get()) }

API调用

 @GET(Api.ENDPOINT.FILMS)
 fun getFilms(): Observable<FilmRequest>

【问题讨论】:

    标签: android unit-testing rx-java retrofit2


    【解决方案1】:

    这是因为在单元测试期间系统调用了你的方法

    searchImpl.getfilms(callback) 
    

    在它完成之前立即调用

    verify(callback)?.onResponseSearchFilm(fackeFilms()) 
    

    所以 getfilms() 方法没有被调用并且你的测试失败了。

    要等到您的 rx 代码完成,您应该在单元测试期间注入并替换您的调度程序。

    更改代码:

    fun getfilms(callback: SearchContract.Callback?){
        disposable = voucherApiServe.getFilms()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                { result -> processFilmSearch(result.data, callback)},
                    { error -> processError(error) }
                )
    }
    

    到:

    fun getfilms(callback: SearchContract.Callback?){
        disposable = voucherApiServe.getFilms()
            .subscribeOn(ioScheduler) //injected scheduler
            .observeOn(mainScheduler) //injected scheduler
            .subscribe(
                { result -> processFilmSearch(result.data, callback)},
                    { error -> processError(error) }
                )
    }
    

    创建 Dagger 模块,如:

    @Module
    class SchedulersModule {
    
        @Provides
        @Named(Names.MAIN)
        fun main(): Scheduler {
            return AndroidSchedulers.mainThread()
        }
    
        @Provides
        @Named(Names.IO)
        fun io(): Scheduler {
            return Schedulers.io()
        }
    
        @Provides
        @Named(Names.COMPUTATION)
        fun computation(): Scheduler {
            return Schedulers.computation()
        }
    
    }
    

    其中 Names 只是一个带有字符串常量的文件(我们知道它必须不同) 并在您的 SearchImpl 类中将这个调度程序注入到构造函数中。

    当您将在测试中创建 SearchImpl 类时,使用 TestScheduler 替换您的凭证ApiServe.getFilms() 链中的调度程序。

    所以。最后一部分是强制 rxjava 的调度程序在你验证结果之前完成工作。

    您的测试应如下所示:

    import io.reactivex.schedulers.TestScheduler
    
    val testScheduler = TestScheduler()
    
    @Before
    fun before() {
        //you create your SearchImpl class here and use testScheduler to replace real schedulers inside it
    }
    
    @Test
    fun loadItems_WhenDataIsAvailable() {
        `when`(api.getFilms()).thenReturn(Observable.just(filmRequestFacke()))
        searchImpl.getfilms(callback)
        testScheduler.triggerActions() //Triggers any actions that have not yet been triggered and that are scheduled to be triggered at or before this Scheduler's present time. 
        verify(callback)?.onResponseSearchFilm(fackeFilms())
    }
    

    所以这个测试会起作用。这也将在 UI 测试期间为您提供帮助(例如,消除 Observable.timer 中的所有延迟)。

    希望它会有所帮助:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-23
      • 2018-09-09
      相关资源
      最近更新 更多