Skip to content
This repository has been archived by the owner on Feb 11, 2022. It is now read-only.

Commit

Permalink
Add the possibility to expect/expectOnly for finite/infinite pipelines
Browse files Browse the repository at this point in the history
  • Loading branch information
Dorvaryn committed May 14, 2015
1 parent 0a12f14 commit 4ce2a7b
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 14 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ buildscript {
jcenter()
}
dependencies {
androidTestCompile 'com.novoda:rxpresso:0.1.3'
androidTestCompile 'com.novoda:rxpresso:0.1.4'
}
}
```
Expand Down
3 changes: 0 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,5 @@ buildscript {
allprojects {
repositories {
jcenter()
maven {
url 'https://dl.bintray.com/novoda/maven/'
}
}
}
6 changes: 4 additions & 2 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,19 @@ android {
}

dependencies {
compile 'com.novoda:rxmocks:0.1.2'
compile 'com.novoda:rxmocks:0.1.3'
compile 'io.reactivex:rxjava:1.0.10'
compile 'com.android.support.test.espresso:espresso-core:2.1'
testCompile 'org.easytesting:fest-assert-core:2.0M10'
testCompile 'org.mockito:mockito-core:1.10.19'
}

publish {
repoName = 'maven'
userOrg = 'novoda'
groupId = 'com.novoda'
artifactId = 'rxpresso'
publishVersion = '0.1.3'
publishVersion = '0.1.4'
description = 'Easy espresso testing for projects using RxJava'
website = 'https://github.com/novoda/rxpresso'
}
53 changes: 45 additions & 8 deletions core/src/main/java/com/novoda/rxpresso/Expect.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public class Expect<T> implements IdlingResource {

/**
* Injects the events from {@code source} into the mocked {@code observable} and wait for an event matching {@code matcher}
* If no event matching {@code matcher} goes through the {@code observable} then the test hangs until an event {@code onCompleted}
* is emitted by the Observable at this points an exception is thrown.
*
* @param matcher A matcher defining what event we are expecting to receive.
* @return A Then object to chain any Espresso actions to execute once {@code observable} received an event matching {@code matcher}
*/
Expand All @@ -43,19 +46,53 @@ public Then expect(RxMatcher<Notification<T>> matcher) {
return new Then();
}

/**
* Injects the events from {@code source} into the mocked {@code observable} and wait for an event matching {@code matcher}
* If an event not matching {@code matcher} is received an exception is thrown.
*
* @param matcher A matcher defining what event we are expecting to receive.
* @return A Then object to chain any Espresso actions to execute once {@code observable} received an event matching {@code matcher}
*/
public Then expectOnly(RxMatcher<Notification<T>> matcher) {
expectOnlyMatching(matcher);
RxMocks.with(repo)
.sendEventsFrom(source)
.to(observable);
return new Then();
}

private void expectAnyMatching(RxMatcher<Notification<T>> matcher) {
RxErrorRethrower.register();
idle.compareAndSet(true, false);
subscription = RxMocks.with(repo)
.getEventsFor(observable)
.subscribe(RxExpect.expect(matcher, new Action1<Notification<T>>() {
@Override
public void call(Notification<T> notification) {
subscription.unsubscribe();
RxErrorRethrower.unregister();
transitionToIdle();
}
}));
.subscribe(
RxExpect.expect(
matcher, new Action1<Notification<T>>() {
@Override
public void call(Notification<T> notification) {
subscription.unsubscribe();
RxErrorRethrower.unregister();
transitionToIdle();
}
}));
}

private void expectOnlyMatching(RxMatcher<Notification<T>> matcher) {
RxErrorRethrower.register();
idle.compareAndSet(true, false);
subscription = RxMocks.with(repo)
.getEventsFor(observable)
.subscribe(
RxExpect.expectOnly(
matcher, new Action1<Notification<T>>() {
@Override
public void call(Notification<T> notification) {
subscription.unsubscribe();
RxErrorRethrower.unregister();
transitionToIdle();
}
}));
}

private void transitionToIdle() {
Expand Down
149 changes: 149 additions & 0 deletions core/src/test/java/com/novoda/rxpresso/RxPressoTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package com.novoda.rxpresso;

import android.support.test.espresso.IdlingResource;

import com.novoda.rxmocks.RxMatcher;
import com.novoda.rxmocks.RxMocks;
import com.novoda.rxmocks.SimpleEvents;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import rx.Notification;
import rx.Observable;

import static com.novoda.rxmocks.RxExpect.any;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

public class RxPressoTest {

public @Rule ExpectedException expectedException = ExpectedException.none();

private TestRepository mockedRepo;
private RxPresso rxPresso;
private IdlingResource.ResourceCallback resourceCallback;

@Before
public void setUp() throws Exception {
mockedRepo = RxMocks.mock(TestRepository.class);
resourceCallback = mock(IdlingResource.ResourceCallback.class);
rxPresso = new RxPresso(mockedRepo);
rxPresso.registerIdleTransitionCallback(resourceCallback);
}

@Test
public void itSendsEventsToMockedObservable() throws Exception {
Observable<Integer> foo = mockedRepo.foo(3);

rxPresso.given(foo)
.withEventsFrom(SimpleEvents.onNext(42))
.expect(any(Integer.class));

Integer result = foo.toBlocking().first();

assertThat(result).isEqualTo(42);
}

@Test
public void itSendsEventsToMockedObservableAccordingToParameter() throws Exception {
Observable<Integer> foo = mockedRepo.foo(3);
Observable<Integer> bar = mockedRepo.foo(1);

rxPresso.given(foo)
.withEventsFrom(SimpleEvents.onNext(42))
.expect(any(Integer.class));
rxPresso.given(bar)
.withEventsFrom(SimpleEvents.onNext(24))
.expect(any(Integer.class));

Integer result = foo.toBlocking().first();
Integer result2 = bar.toBlocking().first();

assertThat(result).isEqualTo(42);
assertThat(result2).isEqualTo(24);
}

@Test
public void resetMocksResetsPipelines() throws Exception {
Observable<Integer> foo = mockedRepo.foo(3);

rxPresso.given(foo)
.withEventsFrom(SimpleEvents.onNext(42))
.expect(any(Integer.class));

rxPresso.resetMocks();

Observable<Integer> bar = mockedRepo.foo(3);

rxPresso.given(bar)
.withEventsFrom(SimpleEvents.<Integer>onCompleted())
.expect(
new RxMatcher<Notification<Integer>>() {
@Override
public boolean matches(Notification<Integer> actual) {
return actual.getKind() == Notification.Kind.OnCompleted;
}

@Override
public String description() {
return "Completed event";
}
}
);

Boolean result = bar.isEmpty().toBlocking().first();

assertThat(result).isTrue();
}

@Test
public void idlingRessourceTransitionsToIdleWhenDataIsDelivered() throws Exception {
Observable<Integer> foo = mockedRepo.foo(3);

rxPresso.given(foo)
.withEventsFrom(SimpleEvents.onNext(42))
.expect(any(Integer.class));

assertThat(rxPresso.isIdleNow()).isFalse();

Integer result = foo.toBlocking().first();

assertThat(rxPresso.isIdleNow()).isTrue();
}

@Test
public void itFailsIfNoEventMatchingMatcherIsReceived() throws Exception {
expectedException.expectMessage("Expected Notification with kind OnNext but completed without matching");
Observable<Integer> foo = mockedRepo.foo(3);

rxPresso.given(foo)
.withEventsFrom(SimpleEvents.<Integer>onCompleted())
.expect(any(Integer.class));

Integer result = foo.toBlocking().first();

assertThat(result).isEqualTo(42);
}

@Test
public void itFailsIfAnEventNotMatchingMatcherIsReceivedWhenUsingExpectOnly() throws Exception {
expectedException.expectMessage("Expected Notification with kind OnNext but got");
Observable<Integer> foo = mockedRepo.foo(3);

rxPresso.given(foo)
.withEventsFrom(Observable.just(42))
.expectOnly(any(Integer.class));

Integer result = foo.toBlocking().first();

assertThat(result).isEqualTo(42);
}

public interface TestRepository {
Observable<Integer> foo(int bar);
}

}

0 comments on commit 4ce2a7b

Please sign in to comment.