2016-12-30 21 views
0
void start() { 
    bar.foo() 
     .filter(i -> i % 2 == 0) 
     .subscribeOn(computation()) 
     .observeOn(io()) 
     .subscribe(new FooSubscriber()); 
} 

この機能では、私がテストに3ポイントを参照してください。このrxJavaコードはどのようにテストできますか?

  1. は、私がbar.foo()呼んでいることを確認します。
  2. filterが正しく実装されていることを確認してください。
  3. 私がbar.foo()に登録していることを確認してください。

最初の点はMockito.verify()でテストするのが簡単です。 3番目の点は、スケジューラを注入してSchedulers.immediate()を使用して、オブザーバをSubjectでモックし、Subject.hasObservers()をチェックします。しかし、私は2番目の点をどのようにテストするかについては考えていません。

このコードをテストするにはどうすればよいですか?私はそれをリファクタリングする必要がありますか?どうやって?

filterは単なる例に過ぎないと思いますが、私は異なる演算子を持つ大きなチェーンを持っています。

+0

私はあなたが ')(' bar.foo呼び出していることを確認したことがないでしょう。あなたのコードの最初のものとして、 'start()'を呼び出すときにそれがうまくいかない場合は、心配するよりはるかに大きな問題があります。 (それが*最初のものでない限り) –

答えて

1

オンにアサートする "観察可能な"動作がなく、ロジックの "途中で"テストコードを取得する必要があるため、このメソッドをテストするのは難しいです。ここで

はあなたが従うことができるシンプルなアプローチである:(あなたが簡単にテストを行うために物事を壊す検討する必要がありますが)

  1. モックのfoo、(そのバーを確認してください)あなたがする必要がある場合は、呼ばれていますbar()から実際のObservableを返します。これは、subscribeが呼ばれたときにコールバックチェーンを巻き戻します。 - これはあなたのチェーンが期待通りに配線されているかどうかをテストします。ブロッキングの方法でメインスレッド上でロジックを実行

  2. を注入スケジューラは、このように同期して、パッケージのプライベートメソッドにnew FooSubscriber()を抽出し、新しい方法をスパイするMockitoを使用して、返す

  3. を理解しやすいテストを保ちます監視サブスクライバを返すことでテスト目的のために模擬できるFooSubscriberのインスタンスを構築するファクトリクラスを注入するか、または注入するかのいずれかを指定します。 - 基本的に、新しいキーワードをハードコードで使用すると、動作をテストできなくなります。

私が必要とする場合は、例を提供することができます、これはあなたが行くことを望みます。

EDIT:上述の両方の方法の例は:

package com.rx; 

import org.junit.Assert; 
import org.junit.Before; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.mockito.Mockito; 
import org.mockito.runners.MockitoJUnitRunner; 
import rx.Observable; 
import rx.Observer; 
import rx.Scheduler; 
import rx.schedulers.Schedulers; 

import java.util.ArrayList; 
import java.util.List; 

@RunWith(MockitoJUnitRunner.class) 
public class TestRxMethod { 

    // prod Bar class - this class tested in isolation in different test. 
    public static class Bar { 

     public Observable<Integer> foo() { 
      return null; 
     } 
    } 

    // prod FooSubscriber class - this class tested in isolation in different test. 
    public static class FooSubscriber implements Observer<Integer> { 

     @Override 
     public void onCompleted() { 
     } 

     @Override 
     public void onError(Throwable e) { 
     } 

     @Override 
     public void onNext(Integer t) { 
     } 
    } 

    // prod FooSubscriberFactory class - this class tested in isolation in different test. 
    public static class FooSubscriberFactory { 

     public Observer<Integer> getInstance() { 
      return null; 
     } 
    } 

    // prod "class under test" 
    public static class UnderTest { 
     private final Bar bar; 
     private final Scheduler computationScheduler; 
     private final Scheduler ioScheduler; 
     private final FooSubscriberFactory fooSubscriberFactory; 

     public UnderTest(Bar bar, Scheduler computationScheduler, Scheduler ioScheduler, 
       FooSubscriberFactory fooSubscriberFactory) { 
      this.bar = bar; 
      this.computationScheduler = computationScheduler; 
      this.ioScheduler = ioScheduler; 
      this.fooSubscriberFactory = fooSubscriberFactory; 
     } 

     public void start() { 
      //@formatter:off 
      bar.foo() 
       .filter(i -> i.intValue() % 2 == 0) 
       .subscribeOn(computationScheduler) 
       .observeOn(ioScheduler) 
       .subscribe(fooSubscriber()); 
      //@formatter:on 
     } 

     // package private so can be overridden by unit test some drawbacks 
     // using this strategy like class cant be made final. - use only 
     // if cant restructure code. 
     Observer<Integer> fooSubscriber() { 
      return fooSubscriberFactory.getInstance(); 
     } 
    } 

    // test Foo subscriber class - test will put set an instance of 
    // this class as the observer on the callback chain. 
    public static class TestFooSubscriber implements Observer<Integer> { 

     public List<Integer> filteredIntegers = new ArrayList<>(); 

     @Override 
     public void onCompleted() { 
      // noop 
     } 

     @Override 
     public void onError(Throwable e) { 
      // noop 
     } 

     @Override 
     public void onNext(Integer i) { 
      // aggregate filtered integers for later assertions 
      filteredIntegers.add(i); 
     } 
    } 

    // mock bar for test 
    private Bar bar; 

    // mock foo subscriber factory for test 
    private FooSubscriberFactory fooSubscriberFactory; 

    // class under test - injected with test dependencies 
    private UnderTest underTest; 

    @Before 
    public void setup() { 
     bar = Mockito.mock(Bar.class); 
     fooSubscriberFactory = Mockito.mock(FooSubscriberFactory.class); 
     underTest = new UnderTest(bar, Schedulers.immediate(), Schedulers.immediate(), fooSubscriberFactory); 
    } 

    // Option #1 - injecting a factory 
    @Test 
    public void start_shouldWork_usingMockedFactory() { 
     // setup bar mock to emit integers 
     Mockito.when(bar.foo()).thenReturn(Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); 

     // setup the subscriber factory to produce an instance of the test subscriber 
     TestFooSubscriber testSubscriber = new TestFooSubscriber(); 
     Mockito.when(fooSubscriberFactory.getInstance()).thenReturn(testSubscriber); 

     underTest.start(); 

     Assert.assertEquals(5, testSubscriber.filteredIntegers.size()); 
     // ... add more assertions as needed per the use cases ... 
    } 

    // Option #2 - spying a protected method 
    @Test 
    public void start_shouldWork_usingSpyMethod() { 
     // setup bar mock to emit integers 
     Mockito.when(bar.foo()).thenReturn(Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); 

     // spy the class under test (use only as a last resort option) 
     underTest = Mockito.spy(underTest); 
     TestFooSubscriber testSubscriber = new TestFooSubscriber(); 
     Mockito.when(underTest.fooSubscriber()).thenReturn(testSubscriber); 

     underTest.start(); 

     Assert.assertEquals(5, testSubscriber.filteredIntegers.size()); 
     // ... add more assertions as needed per the use cases ... 
    } 
} 
+0

あなたはテストをより簡単にするために物を壊すことについて話します。あなたはこのコードを簡単にするためにどのように壊れますか? –

関連する問題