2017-07-11 3 views
0

私はこのようなプレゼンターをテストします:オブザーバーをテストするには?

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) { 
      [email protected]?.populateRecyclerList(t) 
     } 

     override fun onError(e: Throwable) { 
      [email protected]?.showError() 
     } 
    } 
} 

私はオブザーバーを模擬し、成功した場合にエラーまたは戻り値をスローすることを強制的にどのように問題を抱えています。私はmockito/junitを使用しています。誰かがそれを達成する方法を私に指摘することはできますか?多分私のコードはテストできませんか?

答えて

1

observerは、実際にテストすべきではないオブジェクトです。 3番目の開発者が開発した時点ですでにテストされていますが、一部の理由で、サードパーティのライブラリをテストしてコードを破らないようにする必要がある人もいますバージョン間。

したがって、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 
} 

これを行うための別の方法は、(少なくともこのようI通常のコードですが)useCaseobservableを返し、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を模擬することができますこの方法では、それはあなたがコントロールすることができます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 
} 
+0

私は本当に "thenAnswer"メカニズムが好きです。私はあなたのようにテストを書いた、私は非常にうまく動作します。ありがとうございました! – Hype

+0

これは 'thenAnswer'を使用する意図された方法ではないと思うか、ちょっとハックしただけです。それが私の答えを別のやり方で更新するのに役立ちます – Pelocho

1

通常、テストすることは絶対にできない場合はほとんどありません。限り私はそれを見るように、あなたはいくつかのオプションがあります。

  • デフォルト値をコンストラクタにオブザーバーを置く(しかし、これはあなたの依存性注入といくつかの欠点があるかもしれない)関数にオブザーバーを置きますデフォルト値を使用します。これは機能しますが、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>() { 
関連する問題