2014-11-02 22 views
10

Come utilizzare RxJava's TestScheduler? Vengo da uno sfondo .NET ma lo TestScheduler in RxJava non sembra funzionare allo stesso modo dello scheduler di test in .NET rx.Come utilizzare TestScheduler in RxJava

Ecco il codice di esempio che voglio testare

Observable<Long> tick = Observable.interval(1, TimeUnit.SECONDS); 
contactsRepository.find(index) 
    .buffer(MAX_CONTACTS_FETCH) 
    .zipWith(tick, new Func2<List<ContactDto>, Long, List<ContactDto>>() { 
    @Override 
    public List<ContactDto> call(List<ContactDto> contactList, Long aLong) { 
     return contactList; 
    } 
    }).subscribe() 

ho provato:

subscribeOn(testScheduler) 
testScheduler.advanceTimeBy(2, TimeUnit.SECONDS); 
testScheduler.triggerActions(); 

senza fortuna.

+0

Non si passa il 'TestScheduler' a' Observable.Interval'. Questo sarebbe un problema anche in .NET. –

risposta

20

Ho fatto un piccolo esempio di come utilizzare uno TestScheduler. Penso che sia molto simile all'implementazione .NET

@Test 
public void should_test_the_test_schedulers() { 
    TestScheduler scheduler = new TestScheduler(); 
    final List<Long> result = new ArrayList<>(); 
    Observable.interval(1, TimeUnit.SECONDS, scheduler).take(5).subscribe(result::add); 
    assertTrue(result.isEmpty()); 
    scheduler.advanceTimeBy(2, TimeUnit.SECONDS); 
    assertEquals(2, result.size()); 
    scheduler.advanceTimeBy(10, TimeUnit.SECONDS); 
    assertEquals(5, result.size()); 
} 

https://github.com/bric3/demo-rxjava-humantalk/blob/master/src/test/java/demo/humantalk/rxjava/SchedulersTest.java

EDIT Secondo il codice: si dovrebbe passare alla pianificazione per l'operazione Observable.interval, in quanto questo è ciò che si desidera controllare:

TestScheduler scheduler = new TestScheduler(); 

    Observable<Long> tick = Observable.interval(1, TimeUnit.SECONDS, scheduler); 
    Subscription toBeTested = Observable.from(Arrays.asList(1, 2, 3, 4, 5)) 
      .buffer(3) 
      .zipWith(tick, (i, t) -> i) 
      .subscribe(System.out::println); 

    scheduler.advanceTimeBy(2, TimeUnit.SECONDS); 
+1

Sì, è grandioso, ma che ne dici di testare un 'vero/pezzo di codice, restiamo con un metodo con un sottoscrittore Observable che esegue qualche callback su Completa e qualche altro callback su Error. Ho iniettato lo scheduler di test in "subscribeOn" ma senza fortuna da lì. – Calin

+1

Puoi pubblicare del codice per descrivere il tuo problema? – dwursteisen

+0

aggiunto codice di esempio – Calin

7

avete un po 'di classe:

public class SomeClass { 
    public void someMethod() { 
    Observable<Long> tick = Observable.interval(1, TimeUnit.SECONDS); 
    contactsRepository.find(index) 
     .buffer(MAX_CONTACTS_FETCH) 
     .zipWith(tick, new Func2<List<ContactDto>, Long, List<ContactDto>>() { 
     @Override 
     public List<ContactDto> call(List<ContactDto> contactList, Long aLong) { 
      return contactList; 
     } 
     }).subscribe() 
    } 
} 

Cerca nei documenti [Observable.interval][1] e vedrai che opera sull'utilità di pianificazione del calcolo, quindi consente di sovrascriverlo nel nostro test.

public class SomeClassTest { 
    private TestScheduler testScheduler; 

    @Before 
    public void before() { 
    testScheduler = new TestScheduler(); 
    // set calls to Schedulers.computation() to use our test scheduler 
    RxJavaPlugins.setComputationSchedulerHandler(ignore -> testScheduler); 
    } 

    @After 
    public void after() { 
    // reset it 
    RxJavaPlugins.setComputationSchedulerHandler(null); 
    } 

    @Test 
    public void test() { 
    SomeClass someInstance = new SomeClass(); 
    someInstance.someMethod(); 

    // advance time manually 
    testScheduler.advanceBy(1, TimeUnit.SECONDS); 
    } 

Questa soluzione è un miglioramento della risposta accettata come la qualità, l'integrità e la semplicità del codice di produzione è mantenuta.

+1

Grazie! Sto usando 'throttleFirst' ed i miei test hanno fallito perché non ha fatto avanzare il tempo come il mio TestScheduler. –