import junit.framework.Assert; import org.junit.Test; import java.lang.Long; import java.lang.Override; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import rx.Observable; import rx.Scheduler; import rx.functions.Action0; import rx.functions.Action1; import rx.functions.Func1; import rx.observers.TestSubscriber; import rx.schedulers.Schedulers; import rx.schedulers.TestScheduler; import rx.subjects.PublishSubject; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; /** * Example of using test schedulers to inject events anywhere you have an * observable. * * Many Observable operators accept a scheduler parameter. Use it. * * Created by colin on 7/31/15. */ public class Example16Test { // http://stackoverflow.com/questions/26699147/how-to-use-testscheduler-in-rxjava @Test public void should_test_observable_interval() { TestScheduler scheduler = new TestScheduler(); final List<Long> result = new ArrayList<>(); Observable.interval(1, TimeUnit.SECONDS, scheduler) .take(5) .subscribe(new Action1<Long>() { @Override public void call(Long aLong) { result.add(aLong); } }); assertTrue(result.isEmpty()); scheduler.advanceTimeBy(2, TimeUnit.SECONDS); assertEquals(2, result.size()); scheduler.advanceTimeBy(10, TimeUnit.SECONDS); assertEquals(5, result.size()); } @Test public void test_with_blocking_observable() { List<Integer> expected = Arrays.asList(1, 2, 3, 4, 5); List<Integer> ints = Observable.range(1, 5) .take(5) .toList() .toBlocking() .single(); Assert.assertEquals(expected, ints); } @Test public void using_testscheduler_to_simulate_network_events() { // TestScheduler lets you advance time by hand TestScheduler scheduler = Schedulers.test(); TestSubscriber<NetworkResponse> subscriber = new TestSubscriber<>(); // Scheduler.Worker lets you schedule events in time Scheduler.Worker worker = scheduler.createWorker(); // Subjects allow both input and output, so they can be swapped in for // Retrofit calls to unit test your code. final PublishSubject<NetworkResponse> networkSubject = PublishSubject.create(); // schedule a first observable event to occur at 1000 ms worker.schedule(new Action0() { @Override public void call() { // explicitly calling onNext in a worker allows one to // create a very specific test of timed events networkSubject.onNext(new NetworkResponse(401)); } }, 1000, TimeUnit.MILLISECONDS); // schedule a second observable event to occur at 2000 ms worker.schedule(new Action0() { @Override public void call() { networkSubject.onNext(new NetworkResponse(200)); networkSubject.onCompleted(); } }, 2000, TimeUnit.MILLISECONDS); // we must subscribe before anticipating results networkSubject .subscribeOn(scheduler) .subscribe(subscriber); // we can manually advance time using the scheduler and check assertions scheduler.advanceTimeBy(1500, TimeUnit.MILLISECONDS); subscriber.assertReceivedOnNext(Arrays.asList( new NetworkResponse(401))); // awaitTerminalEvent will wait forever if we don't advance time enough scheduler.advanceTimeBy(500, TimeUnit.MILLISECONDS); subscriber.awaitTerminalEvent(); subscriber.assertReceivedOnNext(Arrays.asList( new NetworkResponse(401), new NetworkResponse(200))); // TestSubscriber provides many useful methods subscriber.assertNoErrors(); subscriber.assertValueCount(2); subscriber.assertUnsubscribed(); } @Test public void test_anomalous_network_event() { // TestScheduler lets you advance time by hand TestScheduler scheduler = Schedulers.test(); TestSubscriber<NetworkResponse> subscriber = new TestSubscriber<>(); // Scheduler.Worker lets you schedule events in time Scheduler.Worker worker = scheduler.createWorker(); // Subjects allow both input and output, so they can be swapped in for // Retrofit calls to unit test your code. final PublishSubject<NetworkResponse> networkSubject = PublishSubject.create(); // schedule a first observable event to occur at 1000 ms worker.schedule(new Action0() { @Override public void call() { networkSubject.onError(new TimeoutException()); } }, 10000, TimeUnit.MILLISECONDS); // subscribing so events appear networkSubject .subscribeOn(scheduler) .subscribe(subscriber); scheduler.advanceTimeBy(20000, TimeUnit.MILLISECONDS); subscriber.awaitTerminalEvent(); // we use the class-based assertError method, since it's easier to match subscriber.assertError(TimeoutException.class); subscriber.assertValueCount(0); subscriber.assertUnsubscribed(); } private class NetworkResponse { int httpCode; NetworkResponse(int code) { httpCode = code; } @Override public boolean equals(Object o) { if (o instanceof NetworkResponse) { return ((NetworkResponse) o).httpCode == httpCode; } else { return false; } } } }