From 6c45d01517b977fb8d502b4e0fb2f984af86022e Mon Sep 17 00:00:00 2001 From: Dorvaryn Date: Mon, 24 Aug 2015 18:06:57 +0100 Subject: [PATCH 01/11] Using mockito as a mocking backend as a replacement of RxMocks. This allows to use all of Mockito's powerfull mocking and verifying logic for non Observable related methods. This allows the use of non Interface repos for the mocks. --- build.gradle | 2 +- core/build.gradle | 9 +- .../main/java/com/novoda/rxpresso/Expect.java | 70 +++-- .../java/com/novoda/rxpresso/RxPresso.java | 70 ++--- .../main/java/com/novoda/rxpresso/With.java | 6 +- .../com/novoda/rxpresso/matcher/RxExpect.java | 197 ++++++++++++++ .../novoda/rxpresso/matcher/RxMatcher.java | 9 + .../com/novoda/rxpresso/mock/Functions.java | 11 + .../rxpresso/mock/InfiniteOperator.java | 26 ++ .../java/com/novoda/rxpresso/mock/Pair.java | 66 +++++ .../com/novoda/rxpresso/mock/RxMocks.java | 240 ++++++++++++++++++ .../novoda/rxpresso/mock/SimpleEvents.java | 36 +++ .../rx/subjects/ClearableBehaviorSubject.java | 234 +++++++++++++++++ .../com/novoda/rxpresso/RxExpectTest.java | 54 ++++ .../java/com/novoda/rxpresso/RxMocksTest.java | 124 +++++++++ .../com/novoda/rxpresso/RxPressoTest.java | 12 +- demo/build.gradle | 4 +- .../com/novoda/rxpresso/demo/SampleTest.java | 16 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 19 files changed, 1093 insertions(+), 95 deletions(-) create mode 100644 core/src/main/java/com/novoda/rxpresso/matcher/RxExpect.java create mode 100644 core/src/main/java/com/novoda/rxpresso/matcher/RxMatcher.java create mode 100644 core/src/main/java/com/novoda/rxpresso/mock/Functions.java create mode 100644 core/src/main/java/com/novoda/rxpresso/mock/InfiniteOperator.java create mode 100644 core/src/main/java/com/novoda/rxpresso/mock/Pair.java create mode 100644 core/src/main/java/com/novoda/rxpresso/mock/RxMocks.java create mode 100644 core/src/main/java/com/novoda/rxpresso/mock/SimpleEvents.java create mode 100644 core/src/main/java/rx/subjects/ClearableBehaviorSubject.java create mode 100644 core/src/test/java/com/novoda/rxpresso/RxExpectTest.java create mode 100644 core/src/test/java/com/novoda/rxpresso/RxMocksTest.java diff --git a/build.gradle b/build.gradle index 43067b7..0610880 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:1.2.2' - classpath 'com.novoda:bintray-release:0.2.10' + classpath 'com.novoda:bintray-release:0.3.2' } } diff --git a/core/build.gradle b/core/build.gradle index 8a33f17..fcf5728 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -18,11 +18,12 @@ android { } dependencies { - compile 'com.novoda:rxmocks:0.1.3' - compile 'io.reactivex:rxjava:1.0.10' + compile 'io.reactivex:rxjava:1.0.14' compile 'com.android.support.test.espresso:espresso-core:2.1' + compile 'org.mockito:mockito-core:1.10.19' + compile 'com.google.dexmaker:dexmaker:1.2' + compile 'com.google.dexmaker:dexmaker-mockito:1.2' testCompile 'org.easytesting:fest-assert-core:2.0M10' - testCompile 'org.mockito:mockito-core:1.10.19' } publish { @@ -30,7 +31,7 @@ publish { userOrg = 'novoda' groupId = 'com.novoda' artifactId = 'rxpresso' - publishVersion = '0.1.5' + publishVersion = '0.2.0' description = 'Easy espresso testing for projects using RxJava' website = 'https://github.com/novoda/rxpresso' } diff --git a/core/src/main/java/com/novoda/rxpresso/Expect.java b/core/src/main/java/com/novoda/rxpresso/Expect.java index 26eec47..e19d6b3 100644 --- a/core/src/main/java/com/novoda/rxpresso/Expect.java +++ b/core/src/main/java/com/novoda/rxpresso/Expect.java @@ -2,9 +2,9 @@ import android.support.test.espresso.IdlingResource; -import com.novoda.rxmocks.RxExpect; -import com.novoda.rxmocks.RxMatcher; -import com.novoda.rxmocks.RxMocks; +import com.novoda.rxpresso.matcher.RxExpect; +import com.novoda.rxpresso.matcher.RxMatcher; +import com.novoda.rxpresso.mock.RxMocks; import java.util.concurrent.atomic.AtomicBoolean; @@ -16,15 +16,15 @@ public class Expect implements IdlingResource { - private final Object repo; private final Observable observable; + private final RxMocks repo; private final Observable source; private final AtomicBoolean idle = new AtomicBoolean(true); private Subscription subscription; private ResourceCallback resourceCallback; - Expect(Object repo, Observable source, Observable observable) { + Expect(RxMocks repo, Observable source, Observable observable) { this.repo = repo; this.source = source; this.observable = observable; @@ -40,9 +40,7 @@ public class Expect implements IdlingResource { */ public Then expect(RxMatcher> matcher) { expectAnyMatching(matcher); - RxMocks.with(repo) - .sendEventsFrom(source) - .to(observable); + repo.sendEventsFrom(source).to(observable); return new Then(); } @@ -55,44 +53,42 @@ public Then expect(RxMatcher> matcher) { */ public Then expectOnly(RxMatcher> matcher) { expectOnlyMatching(matcher); - RxMocks.with(repo) - .sendEventsFrom(source) - .to(observable); + repo.sendEventsFrom(source).to(observable); return new Then(); } - private void expectAnyMatching(RxMatcher> matcher) { + private void expectAnyMatching(final RxMatcher> matcher) { RxErrorRethrower.register(); idle.compareAndSet(true, false); - subscription = RxMocks.with(repo) - .getEventsFor(observable) - .subscribe( - RxExpect.expect( - matcher, new Action1>() { - @Override - public void call(Notification notification) { - subscription.unsubscribe(); - RxErrorRethrower.unregister(); - transitionToIdle(); - } - })); + + subscription = repo.getEventsFor(observable).subscribe( + RxExpect.expect( + matcher, new Action1>() { + @Override + public void call(Notification tNotification) { + subscription.unsubscribe(); + RxErrorRethrower.unregister(); + transitionToIdle(); + } + } + )); } - private void expectOnlyMatching(RxMatcher> matcher) { + private void expectOnlyMatching(final RxMatcher> matcher) { RxErrorRethrower.register(); idle.compareAndSet(true, false); - subscription = RxMocks.with(repo) - .getEventsFor(observable) - .subscribe( - RxExpect.expectOnly( - matcher, new Action1>() { - @Override - public void call(Notification notification) { - subscription.unsubscribe(); - RxErrorRethrower.unregister(); - transitionToIdle(); - } - })); + + subscription = repo.getEventsFor(observable).subscribe( + RxExpect.expectOnly( + matcher, new Action1>() { + @Override + public void call(Notification tNotification) { + subscription.unsubscribe(); + RxErrorRethrower.unregister(); + transitionToIdle(); + } + } + )); } private void transitionToIdle() { diff --git a/core/src/main/java/com/novoda/rxpresso/RxPresso.java b/core/src/main/java/com/novoda/rxpresso/RxPresso.java index 6be142c..c98fddd 100644 --- a/core/src/main/java/com/novoda/rxpresso/RxPresso.java +++ b/core/src/main/java/com/novoda/rxpresso/RxPresso.java @@ -2,7 +2,7 @@ import android.support.test.espresso.IdlingResource; -import com.novoda.rxmocks.RxMocks; +import com.novoda.rxpresso.mock.RxMocks; import java.util.ArrayList; import java.util.Collections; @@ -11,9 +11,9 @@ import rx.Observable; import rx.functions.Func1; -public class RxPresso implements IdlingResource { +public final class RxPresso implements IdlingResource { - private final Object[] repositories; + private final List repositories; private final List pendingResources = Collections.synchronizedList(new ArrayList()); private ResourceCallback resourceCallback; @@ -21,31 +21,41 @@ public class RxPresso implements IdlingResource { /** * @param repositories The different mocked repositories you want to control in your tests */ - public RxPresso(Object... repositories) { - this.repositories = repositories; + public static RxPresso init(Object... repositories) { + return new RxPresso(Observable.from(repositories).map(asMockRepoFoo).toList().toBlocking().first()); } /** - /** - * Initiate an action on the given mocked {@code observable} - * @param observable The mocked observable to work with - * @param The type of the observable - * @return The With object to interact with the given mocked {@code observable} + * @param repositories The different mocked repositories you want to control in your tests */ + private RxPresso(List repositories) { + this.repositories = repositories; + } + public With given(Observable observable) { - Object repo = Observable.from(repositories).filter(provides(observable)).toBlocking().first(); + RxMocks repo = Observable.from(repositories).filter(provides(observable)).toBlocking().first(); final With with = new With<>(repo, observable); pendingResources.add(with); - with.registerIdleTransitionCallback(new ResourceCallback() { + with.registerIdleTransitionCallback( + new ResourceCallback() { + @Override + public void onTransitionToIdle() { + pendingResources.remove(with); + if (pendingResources.isEmpty()) { + resourceCallback.onTransitionToIdle(); + } + } + }); + return with; + } + + private Func1 provides(final Observable observable) { + return new Func1() { @Override - public void onTransitionToIdle() { - pendingResources.remove(with); - if (pendingResources.isEmpty()) { - resourceCallback.onTransitionToIdle(); - } + public Boolean call(RxMocks rxMocks) { + return rxMocks.provides(observable); } - }); - return with; + }; } @Override @@ -66,24 +76,12 @@ public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { this.resourceCallback = resourceCallback; } - /** - * Resets all the mocked observables from the repositories registered by RxPresso - */ public void resetMocks() { - for (Object repo : repositories) { - RxMocks.with(repo).resetMocks(); + for (RxMocks repository : repositories) { + repository.resetMocks(); } } - private static Func1 provides(final Observable observable) { - return new Func1() { - @Override - public Boolean call(Object repo) { - return RxMocks.with(repo).provides(observable); - } - }; - } - private static Func1 isIdle = new Func1() { @Override public Boolean call(IdlingResource resource) { @@ -91,4 +89,10 @@ public Boolean call(IdlingResource resource) { } }; + private static Func1 asMockRepoFoo = new Func1() { + @Override + public RxMocks call(Object object) { + return RxMocks.init(object); + } + }; } diff --git a/core/src/main/java/com/novoda/rxpresso/With.java b/core/src/main/java/com/novoda/rxpresso/With.java index 2c21432..70f0193 100644 --- a/core/src/main/java/com/novoda/rxpresso/With.java +++ b/core/src/main/java/com/novoda/rxpresso/With.java @@ -2,16 +2,18 @@ import android.support.test.espresso.IdlingResource; +import com.novoda.rxpresso.mock.RxMocks; + import rx.Observable; public class With implements IdlingResource { - private final Object repo; + private final RxMocks repo; private final Observable observable; private ResourceCallback resourceCallback; private Expect expect; - With(Object repo, Observable observable) { + With(RxMocks repo, Observable observable) { this.repo = repo; this.observable = observable; } diff --git a/core/src/main/java/com/novoda/rxpresso/matcher/RxExpect.java b/core/src/main/java/com/novoda/rxpresso/matcher/RxExpect.java new file mode 100644 index 0000000..427d925 --- /dev/null +++ b/core/src/main/java/com/novoda/rxpresso/matcher/RxExpect.java @@ -0,0 +1,197 @@ +package com.novoda.rxpresso.matcher; + +import rx.Notification; +import rx.Observable; +import rx.functions.Action1; + +public final class RxExpect { + + private RxExpect() { + } + + /** + * Asserts that a given {@code observable} emits an element matching a given {@code matcher} + * + * @param matcher The matcher to use for the assertion + * @param observable The observable to assert against + * @param The type of the observable + */ + public static void expect(RxMatcher> matcher, Observable observable) { + observable.materialize() + .subscribe(expect(matcher)); + } + + /** + * Asserts that a given {@code observable} emits only elements matching a given {@code matcher} + * + * @param matcher The matcher to use for the assertion + * @param observable The observable to assert against + * @param The type of the observable + */ + public static void expectOnly(RxMatcher> matcher, Observable observable) { + observable.materialize() + .subscribe(expectOnly(matcher)); + } + + /** + * Asserts that a given {@code observable} emits an element matching a given {@code matcher} * + * + * @param matcher The matcher to use for the assertion + * @param observable The observable to assert against + * @param matched A callback for when the assertion is matched + * @param The type of the observable + */ + public static void expect(final RxMatcher> matcher, final Observable observable, final Action1> matched) { + observable.materialize() + .subscribe(expect(matcher, matched)); + } + + /** + * Asserts that a given {@code observable} emits only elements matching a given {@code matcher} * + * + * @param matcher The matcher to use for the assertion + * @param observable The observable to assert against + * @param matched A callback for when the assertion is matched + * @param The type of the observable + */ + public static void expectOnly(final RxMatcher> matcher, final Observable observable, final Action1> matched) { + observable.materialize() + .subscribe(expectOnly(matcher, matched)); + } + + /** + * Returns an action to subscribe to an observable to assert if it emits an element matching a given {@code matcher} + * + * @param matcher The matcher to use for the assertion + * @param The type of the observable + * @return The action to subscribe to a materialized observable to assert if a given event is emitted. + */ + public static Action1> expect(final RxMatcher> matcher) { + return expect(matcher, doNothing); + } + + /** + * Returns an action to subscribe to an observable to assert if it emits only elements matching a given {@code matcher} + * + * @param matcher The matcher to use for the assertion + * @param The type of the observable + * @return The action to subscribe to a materialized observable to assert if a given event is emitted. + */ + public static Action1> expectOnly(final RxMatcher> matcher) { + return expectOnly(matcher, doNothing); + } + + /** + * Returns an action to subscribe to an observable to assert if it emits only elements matching a given {@code matcher} * + * + * @param matcher The matcher to use for the assertion + * @param matched A callback for when the assertion is matched + * @param The type of the observable + * @return The action to subscribe to a materialized observable to assert if a given event is emitted. + */ + public static Action1> expectOnly(final RxMatcher> matcher, final Action1> matched) { + return new Action1>() { + @Override + public void call(Notification notification) { + if (matcher.matches(notification)) { + matched.call(notification); + } else { + throw new RuntimeException("Expected " + matcher.description() + " but got " + notification); + } + } + }; + } + + /** + * Returns an action to subscribe to an observable to assert if it emits an element matching a given {@code matcher} * + * + * @param matcher The matcher to use for the assertion + * @param matched A callback for when the assertion is matched + * @param The type of the observable + * @return The action to subscribe to a materialized observable to assert if a given event is emitted. + */ + public static Action1> expect(final RxMatcher> matcher, final Action1> matched) { + return new Action1>() { + + private boolean noMatch = true; + + @Override + public void call(Notification notification) { + if (matcher.matches(notification)) { + noMatch = false; + matched.call(notification); + } + if (notification.getKind() == Notification.Kind.OnCompleted && noMatch) { + throw new RuntimeException("Expected " + matcher.description() + " but completed without matching"); + } + } + }; + } + + /** + * @param clazz The class of the type {@code T} to match + * @param The type to match + * @return a matcher matching any onNext event of a given type {@code T} + */ + public static RxMatcher> any(Class clazz) { + return new RxMatcher>() { + @Override + public boolean matches(Notification actual) { + return actual.getKind() == Notification.Kind.OnNext; + } + + @Override + public String description() { + return "Notification with kind " + Notification.Kind.OnNext; + } + }; + } + + /** + * @param clazz The class of the type {@code T} of the observable to assert against + * @param The type of the observable to assert against + * @return a matcher matching any onError event + */ + public static RxMatcher> anyError(Class clazz) { + return new RxMatcher>() { + @Override + public boolean matches(Notification actual) { + return actual.getKind() == Notification.Kind.OnError; + } + + @Override + public String description() { + return "Notification with kind " + Notification.Kind.OnError; + } + }; + } + + /** + * @param clazz The class of the type {@code T} of the observable to assert against + * @param errorClazz The class of the type {@code V} of the error to match + * @param The type of the observable to assert against + * @param + * @return a matcher matching any onError event with an error a given type {@code V} + */ + public static RxMatcher> anyError(Class clazz, final Class errorClazz) { + return new RxMatcher>() { + @Override + public boolean matches(Notification actual) { + return actual.hasThrowable() && actual.getThrowable().getClass().isAssignableFrom(errorClazz); + } + + @Override + public String description() { + return "Notification with error of type " + errorClazz.getName(); + } + }; + } + + private static final Action1 doNothing = new Action1() { + @Override + public void call(Object o) { + //Do Nothing + } + }; + +} diff --git a/core/src/main/java/com/novoda/rxpresso/matcher/RxMatcher.java b/core/src/main/java/com/novoda/rxpresso/matcher/RxMatcher.java new file mode 100644 index 0000000..9a11532 --- /dev/null +++ b/core/src/main/java/com/novoda/rxpresso/matcher/RxMatcher.java @@ -0,0 +1,9 @@ +package com.novoda.rxpresso.matcher; + +public interface RxMatcher { + + boolean matches(T actual); + + String description(); + +} diff --git a/core/src/main/java/com/novoda/rxpresso/mock/Functions.java b/core/src/main/java/com/novoda/rxpresso/mock/Functions.java new file mode 100644 index 0000000..63cd64c --- /dev/null +++ b/core/src/main/java/com/novoda/rxpresso/mock/Functions.java @@ -0,0 +1,11 @@ +package com.novoda.rxpresso.mock; + +import rx.Observable; + +final class Functions { + + static Observable.Operator infinite() { + return new InfiniteOperator<>(); + } + +} diff --git a/core/src/main/java/com/novoda/rxpresso/mock/InfiniteOperator.java b/core/src/main/java/com/novoda/rxpresso/mock/InfiniteOperator.java new file mode 100644 index 0000000..35d6984 --- /dev/null +++ b/core/src/main/java/com/novoda/rxpresso/mock/InfiniteOperator.java @@ -0,0 +1,26 @@ +package com.novoda.rxpresso.mock; + +import rx.Observable; +import rx.Subscriber; + +class InfiniteOperator implements Observable.Operator { + @Override + public Subscriber call(final Subscriber subscriber) { + return new Subscriber() { + @Override + public void onCompleted() { + //Swallow + } + + @Override + public void onError(Throwable e) { + subscriber.onError(e); + } + + @Override + public void onNext(T t) { + subscriber.onNext(t); + } + }; + } +} diff --git a/core/src/main/java/com/novoda/rxpresso/mock/Pair.java b/core/src/main/java/com/novoda/rxpresso/mock/Pair.java new file mode 100644 index 0000000..fb2ffe7 --- /dev/null +++ b/core/src/main/java/com/novoda/rxpresso/mock/Pair.java @@ -0,0 +1,66 @@ +package com.novoda.rxpresso.mock; + +class Pair { + public final F first; + public final S second; + + /** + * Constructor for a Pair. + * + * @param first the first object in the Pair + * @param second the second object in the pair + */ + public Pair(F first, S second) { + this.first = first; + this.second = second; + } + + /** + * Checks the two objects for equality by delegating to their respective + * {@link Object#equals(Object)} methods. + * + * @param o the {@link Pair} to which this one is to be checked for equality + * @return true if the underlying objects of the Pair are both considered + * equal + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Pair pair = (Pair) o; + + if (first != null ? !first.equals(pair.first) : pair.first != null) { + return false; + } + if (second != null ? !second.equals(pair.second) : pair.second != null) { + return false; + } + + return true; + } + + /** + * Compute a hash code using the hash codes of the underlying objects + * + * @return a hashcode of the Pair + */ + @Override + public int hashCode() { + return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode()); + } + + /** + * Convenience method for creating an appropriately typed pair. + * @param a the first object in the Pair + * @param b the second object in the pair + * @return a Pair that is templatized with the types of a and b + */ + public static Pair create(A a, B b) { + return new Pair(a, b); + } +} diff --git a/core/src/main/java/com/novoda/rxpresso/mock/RxMocks.java b/core/src/main/java/com/novoda/rxpresso/mock/RxMocks.java new file mode 100644 index 0000000..19bd47a --- /dev/null +++ b/core/src/main/java/com/novoda/rxpresso/mock/RxMocks.java @@ -0,0 +1,240 @@ +package com.novoda.rxpresso.mock; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import rx.Notification; +import rx.Observable; +import rx.Subscriber; +import rx.Subscription; +import rx.functions.Action0; +import rx.functions.Action1; +import rx.functions.Func2; +import rx.subjects.ClearableBehaviorSubject; +import rx.subjects.PublishSubject; +import rx.subscriptions.BooleanSubscription; + +import static com.novoda.rxpresso.mock.Functions.infinite; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.when; + +public final class RxMocks { + + private final Object repository; + private final Map observableHashMap = new HashMap<>(); + private final Map, PublishSubject>> mapSubject = new HashMap<>(); + + public static RxMocks mock(Class clazz) { + return init(Mockito.mock(clazz)); + } + + public static RxMocks init(Object repository) { + RxMocks rxMocks = new RxMocks(repository); + rxMocks.setMockResponses(); + return rxMocks; + } + + private RxMocks(Object repository) { + this.repository = repository; + } + + private void setMockResponses() { + for (Method method : repository.getClass().getMethods()) { + if (method.getReturnType().equals(Observable.class) && isMockable(method)) { + setupMockResponseFor(method); + } + } + } + + private boolean isMockable(Method method) { + return !Modifier.isPrivate(method.getModifiers()) + && !Modifier.isProtected(method.getModifiers()) + && !Modifier.isStatic(method.getModifiers()); + } + + public Boolean provides(Observable observable) { + return observableHashMap.containsValue(observable); + } + + public Observable> getEventsFor(Observable observable) { + Pair, PublishSubject> subjectPair = mapSubject.get(observable); + if (subjectPair == null) { + throw new IllegalArgumentException( + "The observable " + observable + + " is not provided by this repo use the provides(Observable o) method to check first"); + } + return Observable.zip(subjectPair.first, subjectPair.second, unzip()) + .lift(clearOnUnsubscribe(observable)); + } + + /** + * Inject the events from given {@code source} into a mocked pipeline + * + * @param source The observable producing the events to inject + * @param The type of this observable + * @return A sender object to define into which pipeline to inject the events. + */ + public RxObservableSender sendEventsFrom(Observable source) { + return new RxObservableSender<>(source); + } + + public class RxObservableSender { + + private final Observable source; + + public RxObservableSender(Observable source) { + this.source = source; + } + + /** + * Send the events from {@code source} to the given mocked {@code observable} + * + * @param observable The mocked observable to inject events into. + */ + public void to(Observable observable) { + ((Observable) source).materialize().lift(infinite()).subscribe(mapSubject.get(observable).first); + } + + } + + public void resetMocks() { + observableHashMap.clear(); + mapSubject.clear(); + } + + private void setupMockResponseFor(Method method) { + try { + when(method.invoke(repository, getArgumentsFor(method))) + .thenAnswer( + new Answer() { + @Override + public Observable answer(InvocationOnMock invocation) throws Throwable { + String key = getKeyFor(invocation.getMethod(), invocation.getArguments()); + if (!observableHashMap.containsKey(key)) { + initialiseMockedObservable(invocation.getMethod(), invocation.getArguments()); + } + return observableHashMap.get(key); + } + } + ); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + + private Object[] getArgumentsFor(Method method) { + List arguments = new ArrayList<>(); + for (Class aClass : method.getParameterTypes()) { + arguments.add(any(aClass)); + } + return arguments.toArray(); + } + + private void initialiseMockedObservable(Method method, Object[] args) { + ClearableBehaviorSubject subject = ClearableBehaviorSubject.create(); + PublishSubject notificationSubject = PublishSubject.create(); + final String keyForArgs = getKeyFor(method, args); + final Observable observable = subject + .dematerialize() + .doOnEach(new NotifyDataEvent(notificationSubject)) + .lift(new SwallowUnsubscribe()); + observableHashMap.put(keyForArgs, observable); + mapSubject.put(observable, new Pair<>(subject, notificationSubject)); + } + + private String getKeyFor(Method method, Object[] args) { + StringBuilder keyBuilder = new StringBuilder(method.getName()); + int index = 0; + for (Class type : method.getParameterTypes()) { + keyBuilder.append('#').append(type.getSimpleName()).append('-').append(args[index++].hashCode()); + } + return keyBuilder.toString(); + } + + private AddUnsubscribe clearOnUnsubscribe(final Object observable) { + return new AddUnsubscribe( + BooleanSubscription.create( + new Action0() { + @Override + public void call() { + mapSubject.get(observable).first.clear(); + } + } + ) + ); + } + + private static class NotifyDataEvent implements Action1> { + + private final PublishSubject> publishSubject; + + public NotifyDataEvent(PublishSubject> publishSubject) { + this.publishSubject = publishSubject; + } + + @Override + public void call(Notification notification) { + publishSubject.onNext((Notification) notification); + } + } + + private static class SwallowUnsubscribe implements Observable.Operator { + + @Override + public Subscriber call(final Subscriber subscriber) { + return new Subscriber() { + @Override + public void onCompleted() { + subscriber.onCompleted(); + } + + @Override + public void onError(Throwable e) { + subscriber.onError(e); + } + + @Override + public void onNext(T t) { + subscriber.onNext(t); + } + }; + } + + } + + private static class AddUnsubscribe implements Observable.Operator { + + private final Subscription unsubscribe; + + private AddUnsubscribe(Subscription unsubscribe) { + this.unsubscribe = unsubscribe; + } + + @Override + public Subscriber call(final Subscriber subscriber) { + subscriber.add(unsubscribe); + return subscriber; + } + + } + + private static Func2 unzip() { + return new Func2() { + @Override + public Notification call(Notification first, Notification second) { + return second; + } + }; + } +} diff --git a/core/src/main/java/com/novoda/rxpresso/mock/SimpleEvents.java b/core/src/main/java/com/novoda/rxpresso/mock/SimpleEvents.java new file mode 100644 index 0000000..916853d --- /dev/null +++ b/core/src/main/java/com/novoda/rxpresso/mock/SimpleEvents.java @@ -0,0 +1,36 @@ +package com.novoda.rxpresso.mock; + +import rx.Observable; + +public final class SimpleEvents { + + private SimpleEvents() { + } + + /** + * @param value The value to emit + * @param The type of the observable + * @return An observable emitting only one onNext event and never completing. (Useful to inject single events in the mocked observables) + */ + public static Observable onNext(T value) { + return Observable.just(value).lift(Functions.infinite()); + } + + /** + * @param error The error to emit + * @param The type of the observable + * @return An observable emitting only one onError event + */ + public static Observable onError(Throwable error) { + return Observable.error(error); + } + + /** + * @param The type of the observable + * @return An observable emitting only one onCompleted event + */ + public static Observable onCompleted() { + return Observable.empty(); + } + +} diff --git a/core/src/main/java/rx/subjects/ClearableBehaviorSubject.java b/core/src/main/java/rx/subjects/ClearableBehaviorSubject.java new file mode 100644 index 0000000..b5b9c9d --- /dev/null +++ b/core/src/main/java/rx/subjects/ClearableBehaviorSubject.java @@ -0,0 +1,234 @@ +package rx.subjects; /** + * Copyright 2014 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.ArrayList; +import java.util.List; + +import rx.annotations.Experimental; +import rx.exceptions.Exceptions; +import rx.functions.Action1; +import rx.internal.operators.NotificationLite; +import rx.subjects.SubjectSubscriptionManager.SubjectObserver; + +/** + * Subject that emits the most recent item it has observed and all subsequent observed items to each subscribed + * {@link rx.Observer}. + *

+ * + *

+ * Example usage: + *

+ *

 {@code
+
+  // observer will receive all events.
+  BehaviorSubject subject = BehaviorSubject.create("default");
+  subject.subscribe(observer);
+  subject.onNext("one");
+  subject.onNext("two");
+  subject.onNext("three");
+
+  // observer will receive the "one", "two" and "three" events, but not "zero"
+  BehaviorSubject subject = BehaviorSubject.create("default");
+  subject.onNext("zero");
+  subject.onNext("one");
+  subject.subscribe(observer);
+  subject.onNext("two");
+  subject.onNext("three");
+
+  // observer will receive only onCompleted
+  BehaviorSubject subject = BehaviorSubject.create("default");
+  subject.onNext("zero");
+  subject.onNext("one");
+  subject.onCompleted();
+  subject.subscribe(observer);
+
+  // observer will receive only onError
+  BehaviorSubject subject = BehaviorSubject.create("default");
+  subject.onNext("zero");
+  subject.onNext("one");
+  subject.onError(new RuntimeException("error"));
+  subject.subscribe(observer);
+  } 
+ *
+ * @param 
+ *          the type of item expected to be observed by the Subject
+ */
+public final class ClearableBehaviorSubject extends Subject {
+    /**
+     * Creates a {@link ClearableBehaviorSubject} without a default item.
+     *
+     * @param 
+     *            the type of item the Subject will emit
+     * @return the constructed {@link ClearableBehaviorSubject}
+     */
+    public static  ClearableBehaviorSubject create() {
+        return create(null, false);
+    }
+    /**
+     * Creates a {@link ClearableBehaviorSubject} that emits the last item it observed and all subsequent items to each
+     * {@link rx.Observer} that subscribes to it.
+     *
+     * @param 
+     *            the type of item the Subject will emit
+     * @param defaultValue
+     *            the item that will be emitted first to any {@link rx.Observer} as long as the
+     *            {@link ClearableBehaviorSubject} has not yet observed any items from its source {@code Observable}
+     * @return the constructed {@link ClearableBehaviorSubject}
+     */
+    public static  ClearableBehaviorSubject create(T defaultValue) {
+        return create(defaultValue, true);
+    }
+    private static  ClearableBehaviorSubject create(T defaultValue, boolean hasDefault) {
+        final SubjectSubscriptionManager state = new SubjectSubscriptionManager();
+        if (hasDefault) {
+            state.set(NotificationLite.instance().next(defaultValue));
+        }
+        state.onAdded = new Action1>() {
+
+            @Override
+            public void call(SubjectObserver o) {
+                o.emitFirst(state.get(), state.nl);
+            }
+            
+        };
+        state.onTerminated = state.onAdded;
+        return new ClearableBehaviorSubject(state, state);
+    }
+
+    private final SubjectSubscriptionManager state;
+    private final NotificationLite nl = NotificationLite.instance();
+
+    protected ClearableBehaviorSubject(OnSubscribe onSubscribe, SubjectSubscriptionManager state) {
+        super(onSubscribe);
+        this.state = state;
+    }
+
+    public void clear() {
+        state.set(null);
+    }
+
+    @Override
+    public void onCompleted() {
+        Object last = state.get();
+        if (last == null || state.active) {
+            Object n = nl.completed();
+            for (SubjectObserver bo : state.terminate(n)) {
+                bo.emitNext(n, state.nl);
+            }
+        }
+    }
+
+    @Override
+    public void onError(Throwable e) {
+        Object last = state.get();
+        if (last == null || state.active) {
+            Object n = nl.error(e);
+            List errors = null;
+            for (SubjectObserver bo : state.terminate(n)) {
+                try {
+                    bo.emitNext(n, state.nl);
+                } catch (Throwable e2) {
+                    if (errors == null) {
+                        errors = new ArrayList();
+                    }
+                    errors.add(e2);
+                }
+            }
+
+            Exceptions.throwIfAny(errors);
+        }
+    }
+
+    @Override
+    public void onNext(T v) {
+        Object last = state.get();
+        if (last == null || state.active) {
+            Object n = nl.next(v);
+            for (SubjectObserver bo : state.next(n)) {
+                bo.emitNext(n, state.nl);
+            }
+        }
+    }
+
+    /* test support */ int subscriberCount() {
+        return state.observers().length;
+    }
+
+    @Override
+    public boolean hasObservers() {
+        return state.observers().length > 0;
+    }
+    /**
+     * Check if the Subject has a value.
+     * 

Use the {@link #getValue()} method to retrieve such a value. + *

Note that unless {@link #hasCompleted()} or {@link #hasThrowable()} returns true, the value + * retrieved by {@code getValue()} may get outdated. + * @return true if and only if the subject has some value and hasn't terminated yet. + */ + @Experimental + public boolean hasValue() { + Object o = state.get(); + return nl.isNext(o); + } + /** + * Check if the Subject has terminated with an exception. + * @return true if the subject has received a throwable through {@code onError}. + */ + @Experimental + public boolean hasThrowable() { + Object o = state.get(); + return nl.isError(o); + } + /** + * Check if the Subject has terminated normally. + * @return true if the subject completed normally via {@code onCompleted()} + */ + @Experimental + public boolean hasCompleted() { + Object o = state.get(); + return nl.isCompleted(o); + } + /** + * Returns the current value of the Subject if there is such a value and + * the subject hasn't terminated yet. + *

The can return {@code null} for various reasons. Use {@link #hasValue()}, {@link #hasThrowable()} + * and {@link #hasCompleted()} to determine if such {@code null} is a valid value, there was an + * exception or the Subject terminated (with or without receiving any value). + * @return the current value or {@code null} if the Subject doesn't have a value, + * has terminated or has an actual {@code null} as a valid value. + */ + @Experimental + public T getValue() { + Object o = state.get(); + if (nl.isNext(o)) { + return nl.getValue(o); + } + return null; + } + /** + * Returns the Throwable that terminated the Subject. + * @return the Throwable that terminated the Subject or {@code null} if the + * subject hasn't terminated yet or it terminated normally. + */ + @Experimental + public Throwable getThrowable() { + Object o = state.get(); + if (nl.isError(o)) { + return nl.getError(o); + } + return null; + } +} diff --git a/core/src/test/java/com/novoda/rxpresso/RxExpectTest.java b/core/src/test/java/com/novoda/rxpresso/RxExpectTest.java new file mode 100644 index 0000000..c06c3ff --- /dev/null +++ b/core/src/test/java/com/novoda/rxpresso/RxExpectTest.java @@ -0,0 +1,54 @@ +package com.novoda.rxpresso; + +import com.novoda.rxpresso.mock.SimpleEvents; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import rx.Observable; + +import static com.novoda.rxpresso.matcher.RxExpect.*; + +public class RxExpectTest { + + public @Rule + ExpectedException expectedException = ExpectedException.none(); + + @Test + public void expectMatchesAccordingToMatcher() throws Exception { + Observable observableToTest = Observable.just(42); + + observableToTest.materialize() + .subscribe(expect(any(Integer.class))); + } + + @Test + public void expectFailsIfNoEventMatchesMatcher() throws Exception { + expectedException.expectMessage("Expected Notification with kind OnError but completed without matching"); + + Observable observableToTest = Observable.just(42); + + observableToTest.materialize() + .subscribe(expect(anyError(Integer.class))); + } + + + + @Test + public void expectOnlyMatchesAccordingToMatcher() throws Exception { + Observable observableToTest = SimpleEvents.onNext(42); + + observableToTest.materialize() + .subscribe(expectOnly(any(Integer.class))); + } + + @Test + public void expectOnlyFailsIfAnEventDoesNotMatchMatcher() throws Exception { + expectedException.expectMessage("Expected Notification with kind OnNext but got"); + Observable observableToTest = Observable.just(42); + + observableToTest.materialize() + .subscribe(expectOnly(any(Integer.class))); + } +} diff --git a/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java b/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java new file mode 100644 index 0000000..3d33fb8 --- /dev/null +++ b/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java @@ -0,0 +1,124 @@ +package com.novoda.rxpresso; + +import com.novoda.rxpresso.mock.RxMocks; +import com.novoda.rxpresso.mock.SimpleEvents; + +import java.lang.reflect.Array; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import rx.Notification; +import rx.Observable; +import rx.functions.Action1; + +import static org.fest.assertions.api.Assertions.assertThat; + +public class RxMocksTest { + + private TestRepository baseRepo; + private RxMocks rxMocks; + + @Before + public void setUp() throws Exception { + baseRepo = Mockito.mock(TestRepository.class); + rxMocks = RxMocks.init(baseRepo); + } + + @Test + public void itSendsEventsToMockedObservable() throws Exception { + Observable foo = baseRepo.foo(3); + + rxMocks.sendEventsFrom(SimpleEvents.onNext(42)) + .to(foo); + + Integer result = foo.toBlocking().first(); + + assertThat(result).isEqualTo(42); + } + + @Test + public void itSendsEventsToMockedObservableAccordingToParameter() throws Exception { + Observable foo = baseRepo.foo(3); + Observable bar = baseRepo.foo(1); + + rxMocks.sendEventsFrom(SimpleEvents.onNext(42)) + .to(foo); + rxMocks.sendEventsFrom(SimpleEvents.onNext(24)) + .to(bar); + + Integer result = foo.toBlocking().first(); + Integer result2 = bar.toBlocking().first(); + + assertThat(result).isEqualTo(42); + assertThat(result2).isEqualTo(24); + } + + @Test + public void itDeterminesWetherAnObservableIsProvidedByAGivenRepository() throws Exception { + Observable foo = baseRepo.foo(3); + + boolean result = rxMocks.provides(foo); + boolean result2 = rxMocks.provides(Observable.just(1)); + + assertThat(result).isTrue(); + assertThat(result2).isFalse(); + } + + @Test + public void itProvidesTheSameObservableForTheSameMethodParamCombination() throws Exception { + Observable foo = baseRepo.foo(3); + Observable bar = baseRepo.foo(3); + + assertThat(foo).isEqualTo(bar); + } + + @Test + public void resetMocksResetsPipelines() throws Exception { + Observable foo = baseRepo.foo(3); + + rxMocks.sendEventsFrom(SimpleEvents.onNext(42)) + .to(foo); + + rxMocks.resetMocks(); + + Observable bar = baseRepo.foo(3); + + rxMocks.sendEventsFrom(SimpleEvents.onCompleted()) + .to(bar); + + Boolean result = bar.isEmpty().toBlocking().first(); + + assertThat(result).isTrue(); + } + + @Test + public void getEventsForDoesNotAffectSubscriptionToMockeObservables() throws Exception { + Observable foo = baseRepo.foo(3); + + final Notification[] test = (Notification[]) Array.newInstance(Notification.class, 1); + rxMocks.getEventsFor(foo) + .subscribe( + new Action1>() { + @Override + public void call(Notification integerNotification) { + test[0] = integerNotification; + } + }); + + rxMocks.sendEventsFrom(SimpleEvents.onNext(42)) + .to(foo); + + assertThat(test[0]).isNull(); + + Integer result = foo.toBlocking().first(); + + assertThat(test[0].getKind()).isEqualTo(Notification.Kind.OnNext); + assertThat(test[0].getValue()).isEqualTo(42); + } + + public interface TestRepository { + Observable foo(int bar); + } +} diff --git a/core/src/test/java/com/novoda/rxpresso/RxPressoTest.java b/core/src/test/java/com/novoda/rxpresso/RxPressoTest.java index 862b259..214076c 100644 --- a/core/src/test/java/com/novoda/rxpresso/RxPressoTest.java +++ b/core/src/test/java/com/novoda/rxpresso/RxPressoTest.java @@ -2,19 +2,19 @@ import android.support.test.espresso.IdlingResource; -import com.novoda.rxmocks.RxMatcher; -import com.novoda.rxmocks.RxMocks; -import com.novoda.rxmocks.SimpleEvents; +import com.novoda.rxpresso.matcher.RxMatcher; +import com.novoda.rxpresso.mock.SimpleEvents; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.mockito.Mockito; import rx.Notification; import rx.Observable; -import static com.novoda.rxmocks.RxExpect.any; +import static com.novoda.rxpresso.matcher.RxExpect.any; import static org.fest.assertions.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -28,9 +28,9 @@ public class RxPressoTest { @Before public void setUp() throws Exception { - mockedRepo = RxMocks.mock(TestRepository.class); + mockedRepo = Mockito.mock(TestRepository.class); resourceCallback = mock(IdlingResource.ResourceCallback.class); - rxPresso = new RxPresso(mockedRepo); + rxPresso = RxPresso.init(mockedRepo); rxPresso.registerIdleTransitionCallback(resourceCallback); } diff --git a/demo/build.gradle b/demo/build.gradle index 830bd8c..f6cc8db 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -25,8 +25,8 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'io.reactivex:rxjava:1.0.10' - compile 'io.reactivex:rxandroid:0.24.0' + compile 'io.reactivex:rxjava:1.0.14' + compile 'io.reactivex:rxandroid:1.0.1' androidTestCompile 'com.android.support.test:runner:0.2' androidTestCompile 'com.android.support.test:rules:0.2' diff --git a/demo/src/androidTest/java/com/novoda/rxpresso/demo/SampleTest.java b/demo/src/androidTest/java/com/novoda/rxpresso/demo/SampleTest.java index e1f3931..f714964 100644 --- a/demo/src/androidTest/java/com/novoda/rxpresso/demo/SampleTest.java +++ b/demo/src/androidTest/java/com/novoda/rxpresso/demo/SampleTest.java @@ -5,22 +5,20 @@ import android.support.test.rule.ActivityTestRule; import android.support.test.runner.AndroidJUnit4; -import com.novoda.rxmocks.RxMocks; -import com.novoda.rxmocks.SimpleEvents; import com.novoda.rxpresso.RxPresso; +import com.novoda.rxpresso.mock.SimpleEvents; import java.io.IOException; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; -import static android.support.test.espresso.matcher.ViewMatchers.withText; -import static com.novoda.rxmocks.RxExpect.any; -import static com.novoda.rxmocks.RxExpect.anyError; +import static android.support.test.espresso.matcher.ViewMatchers.*; +import static com.novoda.rxpresso.matcher.RxExpect.any; +import static com.novoda.rxpresso.matcher.RxExpect.anyError; import static org.hamcrest.Matchers.containsString; @RunWith(AndroidJUnit4.class) @@ -35,10 +33,10 @@ public class SampleTest { protected void beforeActivityLaunched() { SampleApplication application = (SampleApplication) InstrumentationRegistry.getTargetContext().getApplicationContext(); - mockedRepo = RxMocks.mock(DataRepository.class); + mockedRepo = Mockito.mock(DataRepository.class); application.setRepository(mockedRepo); - rxPresso = new RxPresso(mockedRepo); + rxPresso = RxPresso.init(mockedRepo); Espresso.registerIdlingResources(rxPresso); } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0c71e76..e7faee0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip From 78897fa3f78479fb090508be475f09e5c562e13f Mon Sep 17 00:00:00 2001 From: Benjamin AUGUSTIN Date: Tue, 25 Aug 2015 12:23:33 +0100 Subject: [PATCH 02/11] Update README.md --- README.md | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 1e35960..7bccd9a 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,12 @@ Easy Espresso UI testing for Android applications using RxJava. RxPresso makes testing your presentation layer using RxJava as easy as a Unit test. -RxPresso uses [RxMocks](https://github.com/novoda/rxmocks) to generate mocks of your repositories that you can use with RxPresso to control data in your Espresso tests. +RxPresso uses [Mockito](http://mockito.org/) to generate mocks of your repositories that you can use with RxPresso to control data in your Espresso tests. The binding with Espresso Idling resource is handled for you so Espresso will wait until the data you expect to inject in your UI has been delivered to you UI. No more data you don't control in your Espresso test. -At the moment this will only mock methods from the interface returning observables (see Future improvements section). - This project is in its early stages, feel free to comment, and contribute back to help us improve it. ## Adding to your project @@ -26,7 +24,7 @@ buildscript { jcenter() } dependencies { - androidTestCompile 'com.novoda:rxpresso:0.1.5' + androidTestCompile 'com.novoda:rxpresso:0.2.0' } } ``` @@ -34,10 +32,9 @@ buildscript { ## Simple usage -To generate a mocked repo use an interface providing Observables as an abstraction for your repo. -You can now use this interface to generate a mock as shown below. +To generate a mocked repo use simply use Mockito. -**Interfaced repository** +**Example repository** ```java public interface DataRepository { @@ -50,7 +47,7 @@ public interface DataRepository { **Mocking this repository** ```java -DataRepository mockedRepo = RxMocks.mock(DataRepository.class) +DataRepository mockedRepo = Mockito.mock(DataRepository.class) ``` You should then replace the repository used by your activities by this mocked one. @@ -62,7 +59,7 @@ Any other option as long as your UI reads from the mocked repo. ```java DataRepository mockedRepo = getSameRepoUsedByUi(); -RxPresso rxpresso = new RxPresso(mockedRepo); +RxPresso rxpresso = RxPresso.init(mockedRepo); Espresso.registerIdlingResources(rxPresso); ``` @@ -131,14 +128,10 @@ DataRepository mockedRepo = getSameRepoUsedByUi(); AnotherDataRepository mockedRepo2 = getSameSecondRepoUsedByUi(); -RxPresso rxpresso = new RxPresso(mockedRepo, mockedRepo2); +RxPresso rxpresso = RxPresso.init(mockedRepo, mockedRepo2); Espresso.registerIdlingResources(rxPresso); ``` -## Future improvements - -- Support "spying" to allow for non mocked calls to be forwarded to actual implementation. - ## Links Here are a list of useful links: From 976a80fa2563c045fca60b9fd51ef914aa58cf2c Mon Sep 17 00:00:00 2001 From: Dorvaryn Date: Wed, 26 Aug 2015 10:14:03 +0100 Subject: [PATCH 03/11] Rename forgotten foo converter --- core/src/main/java/com/novoda/rxpresso/Expect.java | 4 ++-- core/src/main/java/com/novoda/rxpresso/RxPresso.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/novoda/rxpresso/Expect.java b/core/src/main/java/com/novoda/rxpresso/Expect.java index e19d6b3..7a00c76 100644 --- a/core/src/main/java/com/novoda/rxpresso/Expect.java +++ b/core/src/main/java/com/novoda/rxpresso/Expect.java @@ -57,7 +57,7 @@ public Then expectOnly(RxMatcher> matcher) { return new Then(); } - private void expectAnyMatching(final RxMatcher> matcher) { + private void expectAnyMatching(RxMatcher> matcher) { RxErrorRethrower.register(); idle.compareAndSet(true, false); @@ -74,7 +74,7 @@ public void call(Notification tNotification) { )); } - private void expectOnlyMatching(final RxMatcher> matcher) { + private void expectOnlyMatching(RxMatcher> matcher) { RxErrorRethrower.register(); idle.compareAndSet(true, false); diff --git a/core/src/main/java/com/novoda/rxpresso/RxPresso.java b/core/src/main/java/com/novoda/rxpresso/RxPresso.java index c98fddd..2dff6d8 100644 --- a/core/src/main/java/com/novoda/rxpresso/RxPresso.java +++ b/core/src/main/java/com/novoda/rxpresso/RxPresso.java @@ -22,7 +22,7 @@ public final class RxPresso implements IdlingResource { * @param repositories The different mocked repositories you want to control in your tests */ public static RxPresso init(Object... repositories) { - return new RxPresso(Observable.from(repositories).map(asMockRepoFoo).toList().toBlocking().first()); + return new RxPresso(Observable.from(repositories).map(asRxMocks).toList().toBlocking().first()); } /** @@ -49,7 +49,7 @@ public void onTransitionToIdle() { return with; } - private Func1 provides(final Observable observable) { + private static Func1 provides(final Observable observable) { return new Func1() { @Override public Boolean call(RxMocks rxMocks) { @@ -82,14 +82,14 @@ public void resetMocks() { } } - private static Func1 isIdle = new Func1() { + private static final Func1 isIdle = new Func1() { @Override public Boolean call(IdlingResource resource) { return resource.isIdleNow(); } }; - private static Func1 asMockRepoFoo = new Func1() { + private static final Func1 asRxMocks = new Func1() { @Override public RxMocks call(Object object) { return RxMocks.init(object); From cf6e7f3d2d0d4d532b8b8b0b7b1f3f6e7fd57b4a Mon Sep 17 00:00:00 2001 From: Dorvaryn Date: Wed, 26 Aug 2015 10:31:51 +0100 Subject: [PATCH 04/11] Typo in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7bccd9a..67c8bc3 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ buildscript { ## Simple usage -To generate a mocked repo use simply use Mockito. +To generate a mocked repo simply use Mockito. **Example repository** ```java From 63a205784b5f32517bfed0c9beca6dd642ad08de Mon Sep 17 00:00:00 2001 From: Dorvaryn Date: Wed, 26 Aug 2015 15:33:52 +0100 Subject: [PATCH 05/11] Rename RxMocks to RxMock since it wraps a single mock object --- .../main/java/com/novoda/rxpresso/Expect.java | 6 ++--- .../java/com/novoda/rxpresso/RxPresso.java | 24 ++++++++--------- .../main/java/com/novoda/rxpresso/With.java | 6 ++--- .../mock/{RxMocks.java => RxMock.java} | 14 +++++----- .../java/com/novoda/rxpresso/RxMocksTest.java | 26 +++++++++---------- 5 files changed, 38 insertions(+), 38 deletions(-) rename core/src/main/java/com/novoda/rxpresso/mock/{RxMocks.java => RxMock.java} (96%) diff --git a/core/src/main/java/com/novoda/rxpresso/Expect.java b/core/src/main/java/com/novoda/rxpresso/Expect.java index 7a00c76..515b1fe 100644 --- a/core/src/main/java/com/novoda/rxpresso/Expect.java +++ b/core/src/main/java/com/novoda/rxpresso/Expect.java @@ -4,7 +4,7 @@ import com.novoda.rxpresso.matcher.RxExpect; import com.novoda.rxpresso.matcher.RxMatcher; -import com.novoda.rxpresso.mock.RxMocks; +import com.novoda.rxpresso.mock.RxMock; import java.util.concurrent.atomic.AtomicBoolean; @@ -17,14 +17,14 @@ public class Expect implements IdlingResource { private final Observable observable; - private final RxMocks repo; + private final RxMock repo; private final Observable source; private final AtomicBoolean idle = new AtomicBoolean(true); private Subscription subscription; private ResourceCallback resourceCallback; - Expect(RxMocks repo, Observable source, Observable observable) { + Expect(RxMock repo, Observable source, Observable observable) { this.repo = repo; this.source = source; this.observable = observable; diff --git a/core/src/main/java/com/novoda/rxpresso/RxPresso.java b/core/src/main/java/com/novoda/rxpresso/RxPresso.java index 2dff6d8..0d01064 100644 --- a/core/src/main/java/com/novoda/rxpresso/RxPresso.java +++ b/core/src/main/java/com/novoda/rxpresso/RxPresso.java @@ -2,7 +2,7 @@ import android.support.test.espresso.IdlingResource; -import com.novoda.rxpresso.mock.RxMocks; +import com.novoda.rxpresso.mock.RxMock; import java.util.ArrayList; import java.util.Collections; @@ -13,7 +13,7 @@ public final class RxPresso implements IdlingResource { - private final List repositories; + private final List repositories; private final List pendingResources = Collections.synchronizedList(new ArrayList()); private ResourceCallback resourceCallback; @@ -28,12 +28,12 @@ public static RxPresso init(Object... repositories) { /** * @param repositories The different mocked repositories you want to control in your tests */ - private RxPresso(List repositories) { + private RxPresso(List repositories) { this.repositories = repositories; } public With given(Observable observable) { - RxMocks repo = Observable.from(repositories).filter(provides(observable)).toBlocking().first(); + RxMock repo = Observable.from(repositories).filter(provides(observable)).toBlocking().first(); final With with = new With<>(repo, observable); pendingResources.add(with); with.registerIdleTransitionCallback( @@ -49,11 +49,11 @@ public void onTransitionToIdle() { return with; } - private static Func1 provides(final Observable observable) { - return new Func1() { + private static Func1 provides(final Observable observable) { + return new Func1() { @Override - public Boolean call(RxMocks rxMocks) { - return rxMocks.provides(observable); + public Boolean call(RxMock rxMock) { + return rxMock.provides(observable); } }; } @@ -77,7 +77,7 @@ public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { } public void resetMocks() { - for (RxMocks repository : repositories) { + for (RxMock repository : repositories) { repository.resetMocks(); } } @@ -89,10 +89,10 @@ public Boolean call(IdlingResource resource) { } }; - private static final Func1 asRxMocks = new Func1() { + private static final Func1 asRxMocks = new Func1() { @Override - public RxMocks call(Object object) { - return RxMocks.init(object); + public RxMock call(Object object) { + return RxMock.init(object); } }; } diff --git a/core/src/main/java/com/novoda/rxpresso/With.java b/core/src/main/java/com/novoda/rxpresso/With.java index 70f0193..df3171f 100644 --- a/core/src/main/java/com/novoda/rxpresso/With.java +++ b/core/src/main/java/com/novoda/rxpresso/With.java @@ -2,18 +2,18 @@ import android.support.test.espresso.IdlingResource; -import com.novoda.rxpresso.mock.RxMocks; +import com.novoda.rxpresso.mock.RxMock; import rx.Observable; public class With implements IdlingResource { - private final RxMocks repo; + private final RxMock repo; private final Observable observable; private ResourceCallback resourceCallback; private Expect expect; - With(RxMocks repo, Observable observable) { + With(RxMock repo, Observable observable) { this.repo = repo; this.observable = observable; } diff --git a/core/src/main/java/com/novoda/rxpresso/mock/RxMocks.java b/core/src/main/java/com/novoda/rxpresso/mock/RxMock.java similarity index 96% rename from core/src/main/java/com/novoda/rxpresso/mock/RxMocks.java rename to core/src/main/java/com/novoda/rxpresso/mock/RxMock.java index 19bd47a..830292b 100644 --- a/core/src/main/java/com/novoda/rxpresso/mock/RxMocks.java +++ b/core/src/main/java/com/novoda/rxpresso/mock/RxMock.java @@ -27,23 +27,23 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.when; -public final class RxMocks { +public final class RxMock { private final Object repository; private final Map observableHashMap = new HashMap<>(); private final Map, PublishSubject>> mapSubject = new HashMap<>(); - public static RxMocks mock(Class clazz) { + public static RxMock mock(Class clazz) { return init(Mockito.mock(clazz)); } - public static RxMocks init(Object repository) { - RxMocks rxMocks = new RxMocks(repository); - rxMocks.setMockResponses(); - return rxMocks; + public static RxMock init(Object repository) { + RxMock rxMock = new RxMock(repository); + rxMock.setMockResponses(); + return rxMock; } - private RxMocks(Object repository) { + private RxMock(Object repository) { this.repository = repository; } diff --git a/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java b/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java index 3d33fb8..f415771 100644 --- a/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java +++ b/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java @@ -1,6 +1,6 @@ package com.novoda.rxpresso; -import com.novoda.rxpresso.mock.RxMocks; +import com.novoda.rxpresso.mock.RxMock; import com.novoda.rxpresso.mock.SimpleEvents; import java.lang.reflect.Array; @@ -18,19 +18,19 @@ public class RxMocksTest { private TestRepository baseRepo; - private RxMocks rxMocks; + private RxMock rxMock; @Before public void setUp() throws Exception { baseRepo = Mockito.mock(TestRepository.class); - rxMocks = RxMocks.init(baseRepo); + rxMock = RxMock.init(baseRepo); } @Test public void itSendsEventsToMockedObservable() throws Exception { Observable foo = baseRepo.foo(3); - rxMocks.sendEventsFrom(SimpleEvents.onNext(42)) + rxMock.sendEventsFrom(SimpleEvents.onNext(42)) .to(foo); Integer result = foo.toBlocking().first(); @@ -43,9 +43,9 @@ public void itSendsEventsToMockedObservableAccordingToParameter() throws Excepti Observable foo = baseRepo.foo(3); Observable bar = baseRepo.foo(1); - rxMocks.sendEventsFrom(SimpleEvents.onNext(42)) + rxMock.sendEventsFrom(SimpleEvents.onNext(42)) .to(foo); - rxMocks.sendEventsFrom(SimpleEvents.onNext(24)) + rxMock.sendEventsFrom(SimpleEvents.onNext(24)) .to(bar); Integer result = foo.toBlocking().first(); @@ -59,8 +59,8 @@ public void itSendsEventsToMockedObservableAccordingToParameter() throws Excepti public void itDeterminesWetherAnObservableIsProvidedByAGivenRepository() throws Exception { Observable foo = baseRepo.foo(3); - boolean result = rxMocks.provides(foo); - boolean result2 = rxMocks.provides(Observable.just(1)); + boolean result = rxMock.provides(foo); + boolean result2 = rxMock.provides(Observable.just(1)); assertThat(result).isTrue(); assertThat(result2).isFalse(); @@ -78,14 +78,14 @@ public void itProvidesTheSameObservableForTheSameMethodParamCombination() throws public void resetMocksResetsPipelines() throws Exception { Observable foo = baseRepo.foo(3); - rxMocks.sendEventsFrom(SimpleEvents.onNext(42)) + rxMock.sendEventsFrom(SimpleEvents.onNext(42)) .to(foo); - rxMocks.resetMocks(); + rxMock.resetMocks(); Observable bar = baseRepo.foo(3); - rxMocks.sendEventsFrom(SimpleEvents.onCompleted()) + rxMock.sendEventsFrom(SimpleEvents.onCompleted()) .to(bar); Boolean result = bar.isEmpty().toBlocking().first(); @@ -98,7 +98,7 @@ public void getEventsForDoesNotAffectSubscriptionToMockeObservables() throws Exc Observable foo = baseRepo.foo(3); final Notification[] test = (Notification[]) Array.newInstance(Notification.class, 1); - rxMocks.getEventsFor(foo) + rxMock.getEventsFor(foo) .subscribe( new Action1>() { @Override @@ -107,7 +107,7 @@ public void call(Notification integerNotification) { } }); - rxMocks.sendEventsFrom(SimpleEvents.onNext(42)) + rxMock.sendEventsFrom(SimpleEvents.onNext(42)) .to(foo); assertThat(test[0]).isNull(); From 23dfc411f97e4298419ef823724e7a000d84dad6 Mon Sep 17 00:00:00 2001 From: Dorvaryn Date: Wed, 26 Aug 2015 15:38:24 +0100 Subject: [PATCH 06/11] Rename repository entries to mock --- .../java/com/novoda/rxpresso/RxPresso.java | 22 +++++++++---------- .../java/com/novoda/rxpresso/mock/RxMock.java | 16 +++++++------- .../java/com/novoda/rxpresso/RxMocksTest.java | 2 +- .../com/novoda/rxpresso/RxPressoTest.java | 2 +- .../com/novoda/rxpresso/demo/SampleTest.java | 2 +- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/com/novoda/rxpresso/RxPresso.java b/core/src/main/java/com/novoda/rxpresso/RxPresso.java index 0d01064..e327826 100644 --- a/core/src/main/java/com/novoda/rxpresso/RxPresso.java +++ b/core/src/main/java/com/novoda/rxpresso/RxPresso.java @@ -13,28 +13,28 @@ public final class RxPresso implements IdlingResource { - private final List repositories; + private final List mocks; private final List pendingResources = Collections.synchronizedList(new ArrayList()); private ResourceCallback resourceCallback; /** - * @param repositories The different mocked repositories you want to control in your tests + * @param mocks The different mocked repositories you want to control in your tests */ - public static RxPresso init(Object... repositories) { - return new RxPresso(Observable.from(repositories).map(asRxMocks).toList().toBlocking().first()); + public static RxPresso from(Object... mocks) { + return new RxPresso(Observable.from(mocks).map(asRxMocks).toList().toBlocking().first()); } /** - * @param repositories The different mocked repositories you want to control in your tests + * @param mocks The different mocked repositories you want to control in your tests */ - private RxPresso(List repositories) { - this.repositories = repositories; + private RxPresso(List mocks) { + this.mocks = mocks; } public With given(Observable observable) { - RxMock repo = Observable.from(repositories).filter(provides(observable)).toBlocking().first(); - final With with = new With<>(repo, observable); + RxMock mock = Observable.from(mocks).filter(provides(observable)).toBlocking().first(); + final With with = new With<>(mock, observable); pendingResources.add(with); with.registerIdleTransitionCallback( new ResourceCallback() { @@ -77,7 +77,7 @@ public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { } public void resetMocks() { - for (RxMock repository : repositories) { + for (RxMock repository : mocks) { repository.resetMocks(); } } @@ -92,7 +92,7 @@ public Boolean call(IdlingResource resource) { private static final Func1 asRxMocks = new Func1() { @Override public RxMock call(Object object) { - return RxMock.init(object); + return RxMock.from(object); } }; } diff --git a/core/src/main/java/com/novoda/rxpresso/mock/RxMock.java b/core/src/main/java/com/novoda/rxpresso/mock/RxMock.java index 830292b..3303efc 100644 --- a/core/src/main/java/com/novoda/rxpresso/mock/RxMock.java +++ b/core/src/main/java/com/novoda/rxpresso/mock/RxMock.java @@ -29,26 +29,26 @@ public final class RxMock { - private final Object repository; + private final Object mock; private final Map observableHashMap = new HashMap<>(); private final Map, PublishSubject>> mapSubject = new HashMap<>(); public static RxMock mock(Class clazz) { - return init(Mockito.mock(clazz)); + return from(Mockito.mock(clazz)); } - public static RxMock init(Object repository) { - RxMock rxMock = new RxMock(repository); + public static RxMock from(Object mock) { + RxMock rxMock = new RxMock(mock); rxMock.setMockResponses(); return rxMock; } - private RxMock(Object repository) { - this.repository = repository; + private RxMock(Object mock) { + this.mock = mock; } private void setMockResponses() { - for (Method method : repository.getClass().getMethods()) { + for (Method method : mock.getClass().getMethods()) { if (method.getReturnType().equals(Observable.class) && isMockable(method)) { setupMockResponseFor(method); } @@ -113,7 +113,7 @@ public void resetMocks() { private void setupMockResponseFor(Method method) { try { - when(method.invoke(repository, getArgumentsFor(method))) + when(method.invoke(mock, getArgumentsFor(method))) .thenAnswer( new Answer() { @Override diff --git a/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java b/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java index f415771..0849810 100644 --- a/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java +++ b/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java @@ -23,7 +23,7 @@ public class RxMocksTest { @Before public void setUp() throws Exception { baseRepo = Mockito.mock(TestRepository.class); - rxMock = RxMock.init(baseRepo); + rxMock = RxMock.from(baseRepo); } @Test diff --git a/core/src/test/java/com/novoda/rxpresso/RxPressoTest.java b/core/src/test/java/com/novoda/rxpresso/RxPressoTest.java index 214076c..8166121 100644 --- a/core/src/test/java/com/novoda/rxpresso/RxPressoTest.java +++ b/core/src/test/java/com/novoda/rxpresso/RxPressoTest.java @@ -30,7 +30,7 @@ public class RxPressoTest { public void setUp() throws Exception { mockedRepo = Mockito.mock(TestRepository.class); resourceCallback = mock(IdlingResource.ResourceCallback.class); - rxPresso = RxPresso.init(mockedRepo); + rxPresso = RxPresso.from(mockedRepo); rxPresso.registerIdleTransitionCallback(resourceCallback); } diff --git a/demo/src/androidTest/java/com/novoda/rxpresso/demo/SampleTest.java b/demo/src/androidTest/java/com/novoda/rxpresso/demo/SampleTest.java index f714964..6378311 100644 --- a/demo/src/androidTest/java/com/novoda/rxpresso/demo/SampleTest.java +++ b/demo/src/androidTest/java/com/novoda/rxpresso/demo/SampleTest.java @@ -36,7 +36,7 @@ protected void beforeActivityLaunched() { mockedRepo = Mockito.mock(DataRepository.class); application.setRepository(mockedRepo); - rxPresso = RxPresso.init(mockedRepo); + rxPresso = RxPresso.from(mockedRepo); Espresso.registerIdlingResources(rxPresso); } From 550a92e5d27d5e16192d4f2b352b0e6f861108c8 Mon Sep 17 00:00:00 2001 From: Dorvaryn Date: Wed, 26 Aug 2015 15:39:57 +0100 Subject: [PATCH 07/11] Code wrapping fixes --- .../src/main/java/com/novoda/rxpresso/Expect.java | 6 ++++-- .../main/java/com/novoda/rxpresso/RxPresso.java | 3 ++- core/src/main/java/com/novoda/rxpresso/With.java | 15 +++++++++------ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/com/novoda/rxpresso/Expect.java b/core/src/main/java/com/novoda/rxpresso/Expect.java index 515b1fe..558616e 100644 --- a/core/src/main/java/com/novoda/rxpresso/Expect.java +++ b/core/src/main/java/com/novoda/rxpresso/Expect.java @@ -71,7 +71,8 @@ public void call(Notification tNotification) { transitionToIdle(); } } - )); + ) + ); } private void expectOnlyMatching(RxMatcher> matcher) { @@ -88,7 +89,8 @@ public void call(Notification tNotification) { transitionToIdle(); } } - )); + ) + ); } private void transitionToIdle() { diff --git a/core/src/main/java/com/novoda/rxpresso/RxPresso.java b/core/src/main/java/com/novoda/rxpresso/RxPresso.java index e327826..e433d20 100644 --- a/core/src/main/java/com/novoda/rxpresso/RxPresso.java +++ b/core/src/main/java/com/novoda/rxpresso/RxPresso.java @@ -45,7 +45,8 @@ public void onTransitionToIdle() { resourceCallback.onTransitionToIdle(); } } - }); + } + ); return with; } diff --git a/core/src/main/java/com/novoda/rxpresso/With.java b/core/src/main/java/com/novoda/rxpresso/With.java index df3171f..70f782a 100644 --- a/core/src/main/java/com/novoda/rxpresso/With.java +++ b/core/src/main/java/com/novoda/rxpresso/With.java @@ -20,17 +20,20 @@ public class With implements IdlingResource { /** * Setup the injection of the events from the {@code source} into the mocked {@code observable} + * * @param source An observable providing the events to inject * @return An Expect object to trigger the injection and setup what event to expect and wait for. */ public Expect withEventsFrom(Observable source) { expect = new Expect<>(repo, source, observable); - expect.registerIdleTransitionCallback(new ResourceCallback() { - @Override - public void onTransitionToIdle() { - resourceCallback.onTransitionToIdle(); - } - }); + expect.registerIdleTransitionCallback( + new ResourceCallback() { + @Override + public void onTransitionToIdle() { + resourceCallback.onTransitionToIdle(); + } + } + ); return expect; } From 613f279dd7ecbfb29e8d11cce474784d814cf8ab Mon Sep 17 00:00:00 2001 From: Dorvaryn Date: Wed, 26 Aug 2015 15:47:18 +0100 Subject: [PATCH 08/11] remove legacy src folder --- .../main/java/com/novoda/rxpresso/Expect.java | 14 ++-- .../java/com/novoda/rxpresso/RxPresso.java | 4 +- .../main/java/com/novoda/rxpresso/With.java | 8 +- .../java/com/novoda/rxpresso/RxMocksTest.java | 24 +++--- src/main/AndroidManifest.xml | 1 - src/main/java/com/novoda/rxpresso/Expect.java | 77 ------------------ .../java/com/novoda/rxpresso/RxPresso.java | 81 ------------------- src/main/java/com/novoda/rxpresso/Then.java | 22 ----- src/main/java/com/novoda/rxpresso/With.java | 45 ----------- .../java/rx/plugins/RxErrorRethrower.java | 33 -------- 10 files changed, 25 insertions(+), 284 deletions(-) delete mode 100644 src/main/AndroidManifest.xml delete mode 100644 src/main/java/com/novoda/rxpresso/Expect.java delete mode 100644 src/main/java/com/novoda/rxpresso/RxPresso.java delete mode 100644 src/main/java/com/novoda/rxpresso/Then.java delete mode 100644 src/main/java/com/novoda/rxpresso/With.java delete mode 100644 src/main/java/rx/plugins/RxErrorRethrower.java diff --git a/core/src/main/java/com/novoda/rxpresso/Expect.java b/core/src/main/java/com/novoda/rxpresso/Expect.java index 558616e..ebc9468 100644 --- a/core/src/main/java/com/novoda/rxpresso/Expect.java +++ b/core/src/main/java/com/novoda/rxpresso/Expect.java @@ -17,15 +17,15 @@ public class Expect implements IdlingResource { private final Observable observable; - private final RxMock repo; + private final RxMock mock; private final Observable source; private final AtomicBoolean idle = new AtomicBoolean(true); private Subscription subscription; private ResourceCallback resourceCallback; - Expect(RxMock repo, Observable source, Observable observable) { - this.repo = repo; + Expect(RxMock mock, Observable source, Observable observable) { + this.mock = mock; this.source = source; this.observable = observable; } @@ -40,7 +40,7 @@ public class Expect implements IdlingResource { */ public Then expect(RxMatcher> matcher) { expectAnyMatching(matcher); - repo.sendEventsFrom(source).to(observable); + mock.sendEventsFrom(source).to(observable); return new Then(); } @@ -53,7 +53,7 @@ public Then expect(RxMatcher> matcher) { */ public Then expectOnly(RxMatcher> matcher) { expectOnlyMatching(matcher); - repo.sendEventsFrom(source).to(observable); + mock.sendEventsFrom(source).to(observable); return new Then(); } @@ -61,7 +61,7 @@ private void expectAnyMatching(RxMatcher> matcher) { RxErrorRethrower.register(); idle.compareAndSet(true, false); - subscription = repo.getEventsFor(observable).subscribe( + subscription = mock.getEventsFor(observable).subscribe( RxExpect.expect( matcher, new Action1>() { @Override @@ -79,7 +79,7 @@ private void expectOnlyMatching(RxMatcher> matcher) { RxErrorRethrower.register(); idle.compareAndSet(true, false); - subscription = repo.getEventsFor(observable).subscribe( + subscription = mock.getEventsFor(observable).subscribe( RxExpect.expectOnly( matcher, new Action1>() { @Override diff --git a/core/src/main/java/com/novoda/rxpresso/RxPresso.java b/core/src/main/java/com/novoda/rxpresso/RxPresso.java index e433d20..8bd6605 100644 --- a/core/src/main/java/com/novoda/rxpresso/RxPresso.java +++ b/core/src/main/java/com/novoda/rxpresso/RxPresso.java @@ -78,8 +78,8 @@ public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { } public void resetMocks() { - for (RxMock repository : mocks) { - repository.resetMocks(); + for (RxMock mock : mocks) { + mock.resetMocks(); } } diff --git a/core/src/main/java/com/novoda/rxpresso/With.java b/core/src/main/java/com/novoda/rxpresso/With.java index 70f782a..535e106 100644 --- a/core/src/main/java/com/novoda/rxpresso/With.java +++ b/core/src/main/java/com/novoda/rxpresso/With.java @@ -8,13 +8,13 @@ public class With implements IdlingResource { - private final RxMock repo; + private final RxMock mock; private final Observable observable; private ResourceCallback resourceCallback; private Expect expect; - With(RxMock repo, Observable observable) { - this.repo = repo; + With(RxMock mock, Observable observable) { + this.mock = mock; this.observable = observable; } @@ -25,7 +25,7 @@ public class With implements IdlingResource { * @return An Expect object to trigger the injection and setup what event to expect and wait for. */ public Expect withEventsFrom(Observable source) { - expect = new Expect<>(repo, source, observable); + expect = new Expect<>(mock, source, observable); expect.registerIdleTransitionCallback( new ResourceCallback() { @Override diff --git a/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java b/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java index 0849810..ffa1878 100644 --- a/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java +++ b/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java @@ -17,18 +17,18 @@ public class RxMocksTest { - private TestRepository baseRepo; + private TestRepository mockedRepo; private RxMock rxMock; @Before public void setUp() throws Exception { - baseRepo = Mockito.mock(TestRepository.class); - rxMock = RxMock.from(baseRepo); + mockedRepo = Mockito.mock(TestRepository.class); + rxMock = RxMock.from(mockedRepo); } @Test public void itSendsEventsToMockedObservable() throws Exception { - Observable foo = baseRepo.foo(3); + Observable foo = mockedRepo.foo(3); rxMock.sendEventsFrom(SimpleEvents.onNext(42)) .to(foo); @@ -40,8 +40,8 @@ public void itSendsEventsToMockedObservable() throws Exception { @Test public void itSendsEventsToMockedObservableAccordingToParameter() throws Exception { - Observable foo = baseRepo.foo(3); - Observable bar = baseRepo.foo(1); + Observable foo = mockedRepo.foo(3); + Observable bar = mockedRepo.foo(1); rxMock.sendEventsFrom(SimpleEvents.onNext(42)) .to(foo); @@ -57,7 +57,7 @@ public void itSendsEventsToMockedObservableAccordingToParameter() throws Excepti @Test public void itDeterminesWetherAnObservableIsProvidedByAGivenRepository() throws Exception { - Observable foo = baseRepo.foo(3); + Observable foo = mockedRepo.foo(3); boolean result = rxMock.provides(foo); boolean result2 = rxMock.provides(Observable.just(1)); @@ -68,22 +68,22 @@ public void itDeterminesWetherAnObservableIsProvidedByAGivenRepository() throws @Test public void itProvidesTheSameObservableForTheSameMethodParamCombination() throws Exception { - Observable foo = baseRepo.foo(3); - Observable bar = baseRepo.foo(3); + Observable foo = mockedRepo.foo(3); + Observable bar = mockedRepo.foo(3); assertThat(foo).isEqualTo(bar); } @Test public void resetMocksResetsPipelines() throws Exception { - Observable foo = baseRepo.foo(3); + Observable foo = mockedRepo.foo(3); rxMock.sendEventsFrom(SimpleEvents.onNext(42)) .to(foo); rxMock.resetMocks(); - Observable bar = baseRepo.foo(3); + Observable bar = mockedRepo.foo(3); rxMock.sendEventsFrom(SimpleEvents.onCompleted()) .to(bar); @@ -95,7 +95,7 @@ public void resetMocksResetsPipelines() throws Exception { @Test public void getEventsForDoesNotAffectSubscriptionToMockeObservables() throws Exception { - Observable foo = baseRepo.foo(3); + Observable foo = mockedRepo.foo(3); final Notification[] test = (Notification[]) Array.newInstance(Notification.class, 1); rxMock.getEventsFor(foo) diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml deleted file mode 100644 index 374d72a..0000000 --- a/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/main/java/com/novoda/rxpresso/Expect.java b/src/main/java/com/novoda/rxpresso/Expect.java deleted file mode 100644 index aa1dea1..0000000 --- a/src/main/java/com/novoda/rxpresso/Expect.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.novoda.rxpresso; - -import android.support.test.espresso.IdlingResource; - -import com.novoda.rxmocks.RxExpect; -import com.novoda.rxmocks.RxMatcher; -import com.novoda.rxmocks.RxMocks; - -import java.util.concurrent.atomic.AtomicBoolean; - -import rx.Notification; -import rx.Observable; -import rx.Subscription; -import rx.functions.Action1; -import rx.plugins.RxErrorRethrower; - -public class Expect implements IdlingResource { - - private final Object repo; - private final Observable observable; - private final Observable source; - private final AtomicBoolean idle = new AtomicBoolean(true); - - private Subscription subscription; - private ResourceCallback resourceCallback; - - public Expect(Object repo, Observable source, Observable observable) { - this.repo = repo; - this.source = source; - this.observable = observable; - } - - public Then expect(RxMatcher> matcher) { - expectAnyMatching(matcher); - RxMocks.with(repo) - .sendEventsFrom(source) - .to(observable); - return new Then(); - } - - private void expectAnyMatching(RxMatcher> matcher) { - RxErrorRethrower.register(); - idle.compareAndSet(true, false); - subscription = RxMocks.with(repo) - .getEventsFor(observable) - .subscribe(RxExpect.expect(matcher, new Action1>() { - @Override - public void call(Notification notification) { - subscription.unsubscribe(); - RxErrorRethrower.unregister(); - transitionToIdle(); - } - })); - } - - private void transitionToIdle() { - if (idle.compareAndSet(false, true)) { - resourceCallback.onTransitionToIdle(); - } - } - - @Override - public String getName() { - return "When"; - } - - @Override - public boolean isIdleNow() { - return idle.get(); - } - - @Override - public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { - this.resourceCallback = resourceCallback; - } - -} diff --git a/src/main/java/com/novoda/rxpresso/RxPresso.java b/src/main/java/com/novoda/rxpresso/RxPresso.java deleted file mode 100644 index 9f905d0..0000000 --- a/src/main/java/com/novoda/rxpresso/RxPresso.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.novoda.rxpresso; - -import android.support.test.espresso.IdlingResource; - -import com.novoda.rxmocks.RxMocks; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import rx.Observable; -import rx.functions.Func1; - -public class RxPresso implements IdlingResource { - - private final Object[] repositories; - private final List pendingResources = Collections.synchronizedList(new ArrayList()); - - private ResourceCallback resourceCallback; - - public RxPresso(Object... repositories) { - this.repositories = repositories; - } - - public With given(Observable observable) { - Object repo = Observable.from(repositories).filter(provides(observable)).toBlocking().first(); - final With with = new With<>(repo, observable); - pendingResources.add(with); - with.registerIdleTransitionCallback(new ResourceCallback() { - @Override - public void onTransitionToIdle() { - pendingResources.remove(with); - if (pendingResources.isEmpty()) { - resourceCallback.onTransitionToIdle(); - } - } - }); - return with; - } - - @Override - public String getName() { - return "RxPresso"; - } - - @Override - public boolean isIdleNow() { - if (pendingResources.isEmpty()) { - return true; - } - return Observable.from(pendingResources).all(isIdle).toBlocking().first(); - } - - @Override - public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { - this.resourceCallback = resourceCallback; - } - - public void resetMocks() { - for (Object repo : repositories) { - RxMocks.with(repo).resetMocks(); - } - } - - private static Func1 provides(final Observable observable) { - return new Func1() { - @Override - public Boolean call(Object repo) { - return RxMocks.with(repo).provides(observable); - } - }; - } - - private static Func1 isIdle = new Func1() { - @Override - public Boolean call(IdlingResource resource) { - return resource.isIdleNow(); - } - }; - -} diff --git a/src/main/java/com/novoda/rxpresso/Then.java b/src/main/java/com/novoda/rxpresso/Then.java deleted file mode 100644 index 980497a..0000000 --- a/src/main/java/com/novoda/rxpresso/Then.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.novoda.rxpresso; - -import android.support.test.espresso.DataInteraction; -import android.support.test.espresso.ViewInteraction; -import android.view.View; - -import org.hamcrest.Matcher; - -import static android.support.test.espresso.Espresso.onData; -import static android.support.test.espresso.Espresso.onView; - -public class Then { - - public ViewInteraction thenOnView(Matcher viewMatcher) { - return onView(viewMatcher); - } - - public DataInteraction thenOnData(Matcher dataMatcher) { - return onData(dataMatcher); - } - -} diff --git a/src/main/java/com/novoda/rxpresso/With.java b/src/main/java/com/novoda/rxpresso/With.java deleted file mode 100644 index 732b872..0000000 --- a/src/main/java/com/novoda/rxpresso/With.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.novoda.rxpresso; - -import android.support.test.espresso.IdlingResource; - -import rx.Observable; - -public class With implements IdlingResource { - - private final Object repo; - private final Observable observable; - private ResourceCallback resourceCallback; - private Expect expect; - - public With(Object repo, Observable observable) { - this.repo = repo; - this.observable = observable; - } - - public Expect withEventsFrom(Observable source) { - expect = new Expect<>(repo, source, observable); - expect.registerIdleTransitionCallback(new ResourceCallback() { - @Override - public void onTransitionToIdle() { - resourceCallback.onTransitionToIdle(); - } - }); - return expect; - } - - @Override - public String getName() { - return "With"; - } - - @Override - public boolean isIdleNow() { - return expect == null || expect.isIdleNow(); - } - - @Override - public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { - this.resourceCallback = resourceCallback; - } - -} diff --git a/src/main/java/rx/plugins/RxErrorRethrower.java b/src/main/java/rx/plugins/RxErrorRethrower.java deleted file mode 100644 index b78a809..0000000 --- a/src/main/java/rx/plugins/RxErrorRethrower.java +++ /dev/null @@ -1,33 +0,0 @@ -package rx.plugins; - -public final class RxErrorRethrower { - - private RxErrorRethrower() { - } - - public static void register() { - RxJavaPlugins instance = RxJavaPlugins.getInstance(); - if (!(instance.getErrorHandler() instanceof RethrowerJavaErrorHandler)) { - unregister(); - instance.registerErrorHandler(new RethrowerJavaErrorHandler()); - } - } - - public static void unregister() { - RxJavaPlugins instance = RxJavaPlugins.getInstance(); - RxJavaSchedulersHook schedulersHook = instance.getSchedulersHook(); - RxJavaObservableExecutionHook observableExecutionHook = instance.getObservableExecutionHook(); - instance.reset(); - instance.registerObservableExecutionHook(observableExecutionHook); - instance.registerSchedulersHook(schedulersHook); - } - - private static class RethrowerJavaErrorHandler extends RxJavaErrorHandler { - @Override - public void handleError(Throwable e) { - if (e instanceof RuntimeException) { - throw (RuntimeException) e; - } - } - } -} From df8b2413315f41d7d3a2994f549d6ca4be756237 Mon Sep 17 00:00:00 2001 From: Dorvaryn Date: Wed, 26 Aug 2015 15:50:52 +0100 Subject: [PATCH 09/11] Extract method invocation --- .../java/com/novoda/rxpresso/mock/RxMock.java | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/com/novoda/rxpresso/mock/RxMock.java b/core/src/main/java/com/novoda/rxpresso/mock/RxMock.java index 3303efc..246fc18 100644 --- a/core/src/main/java/com/novoda/rxpresso/mock/RxMock.java +++ b/core/src/main/java/com/novoda/rxpresso/mock/RxMock.java @@ -112,25 +112,29 @@ public void resetMocks() { } private void setupMockResponseFor(Method method) { + when(invoke(method)).thenAnswer( + new Answer() { + @Override + public Observable answer(InvocationOnMock invocation) throws Throwable { + String key = getKeyFor(invocation.getMethod(), invocation.getArguments()); + if (!observableHashMap.containsKey(key)) { + initialiseMockedObservable(invocation.getMethod(), invocation.getArguments()); + } + return observableHashMap.get(key); + } + } + ); + } + + private Object invoke(Method method) { try { - when(method.invoke(mock, getArgumentsFor(method))) - .thenAnswer( - new Answer() { - @Override - public Observable answer(InvocationOnMock invocation) throws Throwable { - String key = getKeyFor(invocation.getMethod(), invocation.getArguments()); - if (!observableHashMap.containsKey(key)) { - initialiseMockedObservable(invocation.getMethod(), invocation.getArguments()); - } - return observableHashMap.get(key); - } - } - ); + return method.invoke(mock, getArgumentsFor(method)); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } + return null; } private Object[] getArgumentsFor(Method method) { From acf78788297319b79782b81bc54a24ee531ad82a Mon Sep 17 00:00:00 2001 From: Dorvaryn Date: Wed, 26 Aug 2015 15:54:37 +0100 Subject: [PATCH 10/11] Rename SimpleEvents to SingleEvent to be more explicit --- .../mock/{SimpleEvents.java => SingleEvent.java} | 4 ++-- .../java/com/novoda/rxpresso/RxExpectTest.java | 4 ++-- .../java/com/novoda/rxpresso/RxMocksTest.java | 14 +++++++------- .../java/com/novoda/rxpresso/RxPressoTest.java | 16 ++++++++-------- .../com/novoda/rxpresso/demo/SampleTest.java | 6 +++--- 5 files changed, 22 insertions(+), 22 deletions(-) rename core/src/main/java/com/novoda/rxpresso/mock/{SimpleEvents.java => SingleEvent.java} (93%) diff --git a/core/src/main/java/com/novoda/rxpresso/mock/SimpleEvents.java b/core/src/main/java/com/novoda/rxpresso/mock/SingleEvent.java similarity index 93% rename from core/src/main/java/com/novoda/rxpresso/mock/SimpleEvents.java rename to core/src/main/java/com/novoda/rxpresso/mock/SingleEvent.java index 916853d..624a74f 100644 --- a/core/src/main/java/com/novoda/rxpresso/mock/SimpleEvents.java +++ b/core/src/main/java/com/novoda/rxpresso/mock/SingleEvent.java @@ -2,9 +2,9 @@ import rx.Observable; -public final class SimpleEvents { +public final class SingleEvent { - private SimpleEvents() { + private SingleEvent() { } /** diff --git a/core/src/test/java/com/novoda/rxpresso/RxExpectTest.java b/core/src/test/java/com/novoda/rxpresso/RxExpectTest.java index c06c3ff..40ec2c0 100644 --- a/core/src/test/java/com/novoda/rxpresso/RxExpectTest.java +++ b/core/src/test/java/com/novoda/rxpresso/RxExpectTest.java @@ -1,6 +1,6 @@ package com.novoda.rxpresso; -import com.novoda.rxpresso.mock.SimpleEvents; +import com.novoda.rxpresso.mock.SingleEvent; import org.junit.Rule; import org.junit.Test; @@ -37,7 +37,7 @@ public void expectFailsIfNoEventMatchesMatcher() throws Exception { @Test public void expectOnlyMatchesAccordingToMatcher() throws Exception { - Observable observableToTest = SimpleEvents.onNext(42); + Observable observableToTest = SingleEvent.onNext(42); observableToTest.materialize() .subscribe(expectOnly(any(Integer.class))); diff --git a/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java b/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java index ffa1878..9177079 100644 --- a/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java +++ b/core/src/test/java/com/novoda/rxpresso/RxMocksTest.java @@ -1,7 +1,7 @@ package com.novoda.rxpresso; import com.novoda.rxpresso.mock.RxMock; -import com.novoda.rxpresso.mock.SimpleEvents; +import com.novoda.rxpresso.mock.SingleEvent; import java.lang.reflect.Array; @@ -30,7 +30,7 @@ public void setUp() throws Exception { public void itSendsEventsToMockedObservable() throws Exception { Observable foo = mockedRepo.foo(3); - rxMock.sendEventsFrom(SimpleEvents.onNext(42)) + rxMock.sendEventsFrom(SingleEvent.onNext(42)) .to(foo); Integer result = foo.toBlocking().first(); @@ -43,9 +43,9 @@ public void itSendsEventsToMockedObservableAccordingToParameter() throws Excepti Observable foo = mockedRepo.foo(3); Observable bar = mockedRepo.foo(1); - rxMock.sendEventsFrom(SimpleEvents.onNext(42)) + rxMock.sendEventsFrom(SingleEvent.onNext(42)) .to(foo); - rxMock.sendEventsFrom(SimpleEvents.onNext(24)) + rxMock.sendEventsFrom(SingleEvent.onNext(24)) .to(bar); Integer result = foo.toBlocking().first(); @@ -78,14 +78,14 @@ public void itProvidesTheSameObservableForTheSameMethodParamCombination() throws public void resetMocksResetsPipelines() throws Exception { Observable foo = mockedRepo.foo(3); - rxMock.sendEventsFrom(SimpleEvents.onNext(42)) + rxMock.sendEventsFrom(SingleEvent.onNext(42)) .to(foo); rxMock.resetMocks(); Observable bar = mockedRepo.foo(3); - rxMock.sendEventsFrom(SimpleEvents.onCompleted()) + rxMock.sendEventsFrom(SingleEvent.onCompleted()) .to(bar); Boolean result = bar.isEmpty().toBlocking().first(); @@ -107,7 +107,7 @@ public void call(Notification integerNotification) { } }); - rxMock.sendEventsFrom(SimpleEvents.onNext(42)) + rxMock.sendEventsFrom(SingleEvent.onNext(42)) .to(foo); assertThat(test[0]).isNull(); diff --git a/core/src/test/java/com/novoda/rxpresso/RxPressoTest.java b/core/src/test/java/com/novoda/rxpresso/RxPressoTest.java index 8166121..58f532e 100644 --- a/core/src/test/java/com/novoda/rxpresso/RxPressoTest.java +++ b/core/src/test/java/com/novoda/rxpresso/RxPressoTest.java @@ -3,7 +3,7 @@ import android.support.test.espresso.IdlingResource; import com.novoda.rxpresso.matcher.RxMatcher; -import com.novoda.rxpresso.mock.SimpleEvents; +import com.novoda.rxpresso.mock.SingleEvent; import org.junit.Before; import org.junit.Rule; @@ -39,7 +39,7 @@ public void itSendsEventsToMockedObservable() throws Exception { Observable foo = mockedRepo.foo(3); rxPresso.given(foo) - .withEventsFrom(SimpleEvents.onNext(42)) + .withEventsFrom(SingleEvent.onNext(42)) .expect(any(Integer.class)); Integer result = foo.toBlocking().first(); @@ -53,10 +53,10 @@ public void itSendsEventsToMockedObservableAccordingToParameter() throws Excepti Observable bar = mockedRepo.foo(1); rxPresso.given(foo) - .withEventsFrom(SimpleEvents.onNext(42)) + .withEventsFrom(SingleEvent.onNext(42)) .expect(any(Integer.class)); rxPresso.given(bar) - .withEventsFrom(SimpleEvents.onNext(24)) + .withEventsFrom(SingleEvent.onNext(24)) .expect(any(Integer.class)); Integer result = foo.toBlocking().first(); @@ -71,7 +71,7 @@ public void resetMocksResetsPipelines() throws Exception { Observable foo = mockedRepo.foo(3); rxPresso.given(foo) - .withEventsFrom(SimpleEvents.onNext(42)) + .withEventsFrom(SingleEvent.onNext(42)) .expect(any(Integer.class)); rxPresso.resetMocks(); @@ -79,7 +79,7 @@ public void resetMocksResetsPipelines() throws Exception { Observable bar = mockedRepo.foo(3); rxPresso.given(bar) - .withEventsFrom(SimpleEvents.onCompleted()) + .withEventsFrom(SingleEvent.onCompleted()) .expect( new RxMatcher>() { @Override @@ -104,7 +104,7 @@ public void idlingRessourceTransitionsToIdleWhenDataIsDelivered() throws Excepti Observable foo = mockedRepo.foo(3); rxPresso.given(foo) - .withEventsFrom(SimpleEvents.onNext(42)) + .withEventsFrom(SingleEvent.onNext(42)) .expect(any(Integer.class)); assertThat(rxPresso.isIdleNow()).isFalse(); @@ -120,7 +120,7 @@ public void itFailsIfNoEventMatchingMatcherIsReceived() throws Exception { Observable foo = mockedRepo.foo(3); rxPresso.given(foo) - .withEventsFrom(SimpleEvents.onCompleted()) + .withEventsFrom(SingleEvent.onCompleted()) .expect(any(Integer.class)); Integer result = foo.toBlocking().first(); diff --git a/demo/src/androidTest/java/com/novoda/rxpresso/demo/SampleTest.java b/demo/src/androidTest/java/com/novoda/rxpresso/demo/SampleTest.java index 6378311..e533a51 100644 --- a/demo/src/androidTest/java/com/novoda/rxpresso/demo/SampleTest.java +++ b/demo/src/androidTest/java/com/novoda/rxpresso/demo/SampleTest.java @@ -6,7 +6,7 @@ import android.support.test.runner.AndroidJUnit4; import com.novoda.rxpresso.RxPresso; -import com.novoda.rxpresso.mock.SimpleEvents; +import com.novoda.rxpresso.mock.SingleEvent; import java.io.IOException; @@ -51,7 +51,7 @@ protected void afterActivityFinished() { @Test public void randomIntegerIsDisplayed() throws Exception { rxPresso.given(mockedRepo.getRandomNumber(10)) - .withEventsFrom(SimpleEvents.onNext(3)) + .withEventsFrom(SingleEvent.onNext(3)) .expect(any(Integer.class)) .thenOnView(withId(R.id.number)) .check(matches(withText(containsString(String.valueOf(3))))); @@ -60,7 +60,7 @@ public void randomIntegerIsDisplayed() throws Exception { @Test public void whenAnErrorOccursAnErrorDialogIsDisplayedShowingErrorMessage() throws Exception { rxPresso.given(mockedRepo.getRandomNumber(10)) - .withEventsFrom(SimpleEvents.onError(new IOException("Not random enough ?!"))) + .withEventsFrom(SingleEvent.onError(new IOException("Not random enough ?!"))) .expect(anyError(Integer.class, IOException.class)) .thenOnView(withText("Not random enough ?!")) .check(matches(isDisplayed())); From c14bc56313c238533fd53725b615e5f25b533ba5 Mon Sep 17 00:00:00 2001 From: Dorvaryn Date: Wed, 26 Aug 2015 15:56:58 +0100 Subject: [PATCH 11/11] Removing useless modifier --- core/src/test/java/com/novoda/rxpresso/RxExpectTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/src/test/java/com/novoda/rxpresso/RxExpectTest.java b/core/src/test/java/com/novoda/rxpresso/RxExpectTest.java index 40ec2c0..557d764 100644 --- a/core/src/test/java/com/novoda/rxpresso/RxExpectTest.java +++ b/core/src/test/java/com/novoda/rxpresso/RxExpectTest.java @@ -12,7 +12,7 @@ public class RxExpectTest { - public @Rule + @Rule ExpectedException expectedException = ExpectedException.none(); @Test @@ -33,8 +33,6 @@ public void expectFailsIfNoEventMatchesMatcher() throws Exception { .subscribe(expect(anyError(Integer.class))); } - - @Test public void expectOnlyMatchesAccordingToMatcher() throws Exception { Observable observableToTest = SingleEvent.onNext(42);