Cómo probar el observador?

Yo pondría a testing al presentador así:

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() } } } 

Tengo un problema para burlarme del observador y forzarlo a arrojar errores o devolver valor al éxito. Estoy usando mockito / junit. ¿Alguien puede indicarme cómo lograrlo? ¿Tal vez mi código no sea comprobable?

Un observer es un object que no debe ser realmente probado. Ya ha sido probado cuando ha sido desarrollado por un tercer desarrollador, aunque hay algunas personas que dicen, con una razón, que también debes probar una biblioteca de terceros para asegurarte de que no rompa tu código. entre versiones.

Entonces, si no testing al observer … ¿cómo testing su código? Simplemente, lo que realmente necesita probar es el presentador en sí. El código que se ejecuta dentro del observer es parte del presentador. Entonces, en lugar de burlarse, el observer burla del 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 } 

Otra forma de hacer esto (al less esta es la forma en que usualmente código) es hacer que useCase devuelva un elemento observable y suscribirlo en el 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()) } } 

De esta forma, puedes burlar fácilmente tu useCase para que devuelva un Subject que puedas controlar:

 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 } 

Por lo general, no hay muchos casos en los que no sea posible realizar la testing. Por lo que yo veo, tienes algunas opciones:

  • Coloque al observador en el constructor con un valor pnetworkingeterminado (pero esto podría tener algunas desventajas con su dependency injection)
  • Ponga al observador en la function con un valor pnetworkingeterminado. Esto funcionaría, pero debes elegir si tu API debe contener esto
  • Usa el observador como propiedad. En la testing, puedes anular esta.

Todas estas variantes funcionarían y se enumeran aquí:

 // 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>() { ... } 

Sería aún más agradable si nos usas una DisposableSingleObserverFactory y creas el observador cuando sea necesario.

 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>() {