android - 在 MVP 中使用 Retrofit 测试 RxJava 调用得到通缉但未被调用

标签 android unit-testing rx-java retrofit2

我正在尝试使用改造和 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>

最佳答案

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

searchImpl.getfilms(callback) 

在它完成之前立即调用

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

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

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

更改代码:

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 类中将此调度程序注入(inject)构造函数。

当您将创建被测 SearchImpl 类时,使用 TestScheduler 替换您的 voucherApiServe.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 中的所有延迟)。

希望对你有帮助:)

关于android - 在 MVP 中使用 Retrofit 测试 RxJava 调用得到通缉但未被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58518217/

相关文章:

android - 可扩展的 ListView 组指示器在获得焦点时自动更改

unit-testing - 如何使用 Carrierwave + FactoryGirl 测试上传

unit-testing - WP7 : Getting started with UnitTest Framework: XamlParseException

java - RxJava - 嵌套的 Observables? ( retrofit )

android - 如何修复尝试通过改造抛出 OutOfMemoryError 时抛出的 OutOfMemoryError

android - ScrollView 内的多个可滚动 TextView

android - 无法在我的 Mac 上找到 keytool 来签署我的 apk 文件

unit-testing - 无法解析符号: is in this context

java - 将值与 Java8 流结合

安卓,RX : what put to UI thread - collections or elements?