【问题标题】:How to write unit test for RxJava CompositeSubscription如何为 RxJava CompositeSubscription 编写单元测试
【发布时间】:2017-06-02 12:24:22
【问题描述】:
@Override public void onBarcodeReceived(final String barcode) {
    view.showProgress();
    if (!textUtil.isEmpty(barcode)) {
      subscriptions.add(
          interactor.getSearchResultByBarcode(barcode).subscribe(subscriberForSearchResults(true)));
    }
  }

  private Subscriber<PriceAndStockActivityViewModel> subscriberForSearchResults(
      boolean fromBarcode) {
    return new BaseSubscriber<PriceAndStockActivityViewModel>() {
      @Override public void onNext(PriceAndStockActivityViewModel priceAndStockActivityViewModel) {
        super.onNext(priceAndStockActivityViewModel);
        view.updateView(priceAndStockActivityViewModel);
      }

      @Override public void onError(Throwable e) {
        super.onError(e);
        view.hideProgress();
        view.organizeScreenComponentsByVisibility(true);
        view.onError(e);
      }
    };
  }

我想测试名为 onBarcodeReceived 的方法,如下所示

@Test public void should_updateViewByViewModel_when_AnyBarcodeReceived() {
    String barcode = "123123123";
    PriceAndStockActivityViewModel viewModel = getPriceAndStockActivityViewModel(barcode);
    when(textUtil.isEmpty(barcode)).thenReturn(false);
    when(interactor.getSearchResultByBarcode(anyString())).thenReturn(Observable.just(viewModel));

    presenter.onBarcodeReceived(barcode);

    verify(view).showProgress();
    verify(interactor).getSearchResultByBarcode(anyString());
    verify(view).updateView(any(PriceAndStockActivityViewModel.class));
  }

由于 onNext 在不同的线程中运行,因此通常不会到达 view.updateView。它看起来很简单,但我找不到如何解决它。有没有办法验证updateView?

【问题讨论】:

  • 我投票决定将此问题作为题外话结束,因为实际上我的实现是正确的,但由于我的原因出现了不同的错误。与代码没有任何关系。人们可能会混淆这个问题。请删除它。

标签: android unit-testing junit rx-java


【解决方案1】:

为了等待另一个线程完成,您可以使用此 Mockito 功能:verify with timeout

verify(view, timeout(100)).updateView(any(PriceAndStockActivityViewModel.class));

或者使用一些线程同步的方法,比如CountDownLatch。请参阅 Mockito here 的示例。

【讨论】:

  • 这不仅仅是线程问题。相信rxjava一定有问题...
  • @MustafaGüven 你试过添加超时吗?我在这里没有看到任何关于 RxJava 的内容。
【解决方案2】:

我认为getSearchResultByBarcode() 在后台线程上工作。所以我想知道您如何能够从这个后台线程更改您的 UI?

我会将subscriber 的执行更改为Android 的主线程,以便您可以安全地操作视图,无论getSearchResultByBarcode() 的线程将来是否发生变化。但是不会直接硬编码Scheduler,而是让我们将它注入到presenter类中,例如通过构造函数。当然,当你创建“真正的”演示者时,你会传入AndroidSchedulers.mainThread()

public MyPresenter(, Scheduler observeScheduler) {
    ...
    this.observeScheduler = observeScheduler;
}

....

@Override 
public void onBarcodeReceived(final String barcode) {
     view.showProgress();
     if (!textUtil.isEmpty(barcode)) {
          subscriptions.add(interactor.getSearchResultByBarcode(barcode)
                .observeOn(observeScheduler)
                .subscribe(subscriberForSearchResults(true)));
     }
}

然后在您的测试中,在构建 Presenter 时,您将使用 Schedulers.immediate()(如果您使用的是 RxJava 1.x 或 Schedulers.trampoline(),如果您使用的是 RxJava 2.x 版本。这应该可以在没有在您的单元测试中使用任何 timeout()s 与 Mockito ...毕竟您希望它们尽可能快地运行。

还有一件不相关的事情 - 您可以使用 org.apache.commons.lang3.StringUtils 代替 android.text.TextUtils - 它具有大致相同的功能,但您不需要在单元测试中模拟它。

【讨论】:

    猜你喜欢
    • 2017-02-05
    • 1970-01-01
    • 1970-01-01
    • 2018-01-17
    • 2012-01-06
    • 2019-03-17
    • 2016-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多