-
Notifications
You must be signed in to change notification settings - Fork 0
TestSubscriber
TestSubscriber is a subscriber that makes it easy to test Observables. Subscribe it to any Observable and the TestSubscriber will record all events the Observable emits and allow you to make assertions against them. Assertions use Hamcrest matchers to make it easy to write readable tests that provide detailed failure messages. While allowing the test to wait for specific events to be emitted so that there are never race conditions in your tests.
@Test
public void someTest() throws Exception{
final TestSubscriber<String> testSubscriber = new TestSubscriber<>();
new ObservableBuilder<String>()
.emit("Glork")
.emit("flork")
.emit("fork")
.emit("spoon")
.sleep(1000)
.error(new Exception("There is no spoon"))
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
.subscribe(testSubscriber);
testSubscriber.awaitEvent(isErrorThat(hasMessageThat(containsString("no spoon"))));
testSubscriber.assertDoesNotHaveEvent(isError(IOException.class));
testSubscriber.assertHasEvent(isValue("spoon"));
testSubscriber.assertWellBehaved();
testSubscriber.beginAssertionChain()
.assertNextEvent(isValue("Glork"))
.assertNextEvent(isValueThat(containsString("ork")))
.assertNextEvent(isValueThat(endsWith("k")))
.assertNextEvent(isValue("spoon"))
.assertNextEvent(isErrorThat(hasMessageThat(containsString("no spoon"))));
}
There are a few simple assertions that can be made directly against the TestSubscriber
- assertHasEvent ** Will assert that the TestSubscriber received an event that matches the given matcher
- assertDoesNotHaveEvent ** Will assert that the TestSubscriber never received an event that matches the given matcher
- assertWellBehaved ** Will assert that the TestSubscriber did not receive more than one completion or error event
Assertion chains allow you to assert that specific events took place in a specific order. Simply call beginAssertionChain() to start the chain and you can make all of your assertions against the chain that is returned. Each assertion will walk through the chain of events received by the TestSubscriber and run your assertions against them. The following calls are available on the assertion chains:
- assertNextEvent
- Asserts that the next received event matches the given matcher
- ignoreNextEvent
- Skips an event in the chain and makes no assertions, this is useful if you don't care about a particular event in an event chain
- ignoreNextEvents
- Like assertNextEvent but skips a given number of events
- ignoreUntilEvent
- Skips all events up until an event that matches the given matcher, this will fail if no event matches said matcher. There is also a version that will allow you to skip events until a given number of matching events are found.
- assertNoRemainingEvents
- Asserts that all received events have been checked or skipped by the AssertionChain
The hardest thing about testing complex Observables when working with Schedulers is race conditions. You have to wait for an Observable to emit, which means holding the test thread until the right time. Unfortunately waiting the right amount of time consistently can be difficult. TestSubscriber makes this easy by providing methods that hold the current thread until specific event has occurred. Simply call await event with a matcher for an event, and the test will hold until a matching event has occured, there are even versions that allow you to specify timeouts and how many times the event should be emited before holding the thread.
##Failing The failure messages from all assertions are carefully crafted to provide as much information as possible during a failure. This makes hunting down bugs easy.
All failure messages dump the whole event chain so you can see exactly how the Observable behaved during the test. And assertions that check specific points in the event chain will even points out exactly where a failure occurred.
java.lang.AssertionError:
Expected: onNext with value matching: is "knife"
but: was onNext("spoon")
event chain:
onNext("Glork")
onNext("flork")
onNext("fork")
-------> onNext("spoon")
onError(<java.lang.Exception: There is no spoon>)