Тестирование вызова RxJava с Retrofit в MVP получает Wanted, но не вызывается - PullRequest
1 голос
/ 23 октября 2019

Я пытаюсь проверить мой серверный вызов с помощью retrofit и rxJava. Я использую шаблон MVP с koin, и у меня возникают некоторые проблемы, когда я пытаюсь проверить метод, который выполняет вызов для получения данных с сервера.

У меня есть prenter, который вызывает интеракторчтобы получить данные. Interactor DI сделан с koin.

Я провел некоторое исследование здесь и в Google, и все примеры, которые я наблюдал, не работают для меня.

Ошибка, которую яесть это:

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>

1 Ответ

0 голосов
/ 14 ноября 2019

Это связано с тем, что во время модульных тестов системный вызов вашего метода

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 для замены планировщиков внутри цепочки 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())
}

Так что этот тест будет работать. Это также поможет вам во время тестов пользовательского интерфейса (например, чтобы убрать все задержки в Observable.timer).

Надеюсь, это поможет:)

...