Как проверить наблюдателя?

Я бы испытал докладчика следующим образом:

class MostPopularPresenter @Inject constructor(val mostPopularUseCase: MostPopularUseCase) : Presenter<MostPopularView>() { fun requestMostPopular(page: Int, update: Boolean) { if (page <= 6) mostPopularUseCase.execute(MostPopularObserver(), MostPopularUseCase.Params.createQuery(page, 15, update)) } inner class MostPopularObserver : DisposableSingleObserver<MostPopularModel>() { override fun onSuccess(t: MostPopularModel) { this@MostPopularPresenter.view?.populateRecyclerList(t) } override fun onError(e: Throwable) { this@MostPopularPresenter.view?.showError() } } } 

У меня есть проблема, как издеваться над наблюдателем и заставить его бросать ошибку или возвращать ценность успеха. Я использую mockito / junit. Может кто-нибудь указать мне, как его достичь? Может быть, мой код неуместен?

observer – это объект, который не должен быть действительно проверен. Он уже был протестирован, когда он был разработан третьим разработчиком, хотя есть некоторые люди, которые говорят с определенной долей, что вы также должны протестировать стороннюю библиотеку, чтобы гарантировать, что она не сломает ваш код между версиями.

Итак, если вы не проверяете observer … как вы проверяете свой код? Просто, что вам действительно нужно проверить, сам ведущий . Код, выполняемый внутри observer является частью ведущего. Поэтому вместо издевательств observer издевается над useCase :

 test useCaseFails() { val usecase = // mock use case when(usecase.execute(...)) .thenAnswer(/* receive the observer as first parameter and make it emit an error */) val presenter = ... presenter.requestMostPopular(...) // assert that presenter.view?.showError has been called } 

Другой способ сделать это (по крайней мере, так я обычно использую код) – заставить useCase возвратить observable и подписаться на него в presenter :

 class MostPopularPresenter @Inject constructor(val mostPopularUseCase: MostPopularUseCase) : Presenter<MostPopularView>() { private var lateinit observer : Disposable fun requestMostPopular(page: Int, update: Boolean) { if (page <= 6) disposable = mostPopularUseCase.execute(MostPopularUseCase.Params.createQuery(page, 15, update)) .subscribe(t -> view?.populateRecyclerList(t), e -> view?.showError()) } } 

Таким образом, вы можете легко useCase ваш useCase чтобы он возвращал Subject вы можете контролировать:

 test useCaseFails() { val usecase = // mock use case val subject = PublishSubject() when(usecase.execute(...)) .thenReturn(subject) val presenter = ... presenter.requestMostPopular(...) subject.emitError(...) // <- pseudocode // assert that presenter.view?.showError has been called } при test useCaseFails() { val usecase = // mock use case val subject = PublishSubject() when(usecase.execute(...)) .thenReturn(subject) val presenter = ... presenter.requestMostPopular(...) subject.emitError(...) // <- pseudocode // assert that presenter.view?.showError has been called } 

Обычно не так много случаев, когда это невозможно проверить. Насколько я вижу, у вас есть несколько вариантов:

  • Поместите наблюдателя в конструктор со значением по умолчанию (но это может иметь некоторые недостатки с вашей инъекцией зависимостей)
  • Поместите наблюдателя в функцию со значением по умолчанию. Это будет работать, но вы должны выбрать, должен ли ваш API содержать это
  • Использовать наблюдателя как свойство. В тесте вы можете переопределить это.

Все эти варианты будут работать и перечислены здесь:

 // observer in constructor class MostPopularPresenter @Inject constructor(val mostPopularUseCase: MostPopularUseCase, val observer: DisposableSingleObserver<MostPopularModel> = MostPopularObserver()) : Presenter<MostPopularView>() { // observer as property internal var observer: DisposableSingleObserver<MostPopularModel> = MostPopularObserver() // observer in function fun requestMostPopular(page: Int, update: Boolean, observer: DisposableSingleObserver<MostPopularModel> = MostPopularObserver()) { if (page <= 6) mostPopularUseCase.execute(observer, MostPopularUseCase.Params.createQuery(page, 15, update)) } } internal class MostPopularObserver : DisposableSingleObserver<MostPopularModel>() { ... } 

Было бы даже приятнее, если бы вы использовали DisposableSingleObserverFactory и создавали наблюдателя, когда это было необходимо.

 class MostPopularPresenter @Inject constructor(val mostPopularUseCase: MostPopularUseCase, val observerFactory: DisposableSingleObserverFactory<MostPopularModel> = MostPopularObserverFactorty()) : Presenter<MostPopularView>() { internal var observerFactory: DisposableSingleObserverFactory<MostPopularModel> = MostPopularObserverFactory() fun requestMostPopular(page: Int, update: Boolean, observerFactory: DisposableSingleObserverFactory<MostPopularModel> = MostPopularObserver()) { if (page <= 6) mostPopularUseCase.execute(observerFactory.create(), MostPopularUseCase.Params.createQuery(page, 15, update)) } } internal class MostPopularObserver : DisposableSingleObserver<MostPopularModel>() {