Skip to content

Commit

Permalink
Merge pull request #749 from wehjin/splittests
Browse files Browse the repository at this point in the history
Separated Android test code from source.
  • Loading branch information
benjchristensen committed Jan 14, 2014
2 parents 52db70c + 22233ac commit 7bae419
Show file tree
Hide file tree
Showing 6 changed files with 379 additions and 275 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,6 @@
*/
package rx.android.observables;

import static org.mockito.Mockito.verify;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import rx.Observable;
import rx.Observer;
import rx.operators.OperationObserveFromAndroidComponent;
Expand Down Expand Up @@ -108,52 +98,4 @@ public static <T> Observable<T> fromFragment(Object fragment, Observable<T> sour
throw new IllegalArgumentException("Target fragment is neither a native nor support library Fragment");
}
}

@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public static final class AndroidObservableTest {

// support library fragments
private FragmentActivity fragmentActivity;
private android.support.v4.app.Fragment supportFragment;

// native fragments
private Activity activity;
private Fragment fragment;

@Mock
private Observer<String> observer;

@Before
public void setup() {
MockitoAnnotations.initMocks(this);
supportFragment = new android.support.v4.app.Fragment();
fragmentActivity = Robolectric.buildActivity(FragmentActivity.class).create().get();
fragmentActivity.getSupportFragmentManager().beginTransaction().add(supportFragment, null).commit();

fragment = new Fragment();
activity = Robolectric.buildActivity(Activity.class).create().get();
activity.getFragmentManager().beginTransaction().add(fragment, null).commit();
}

@Test
public void itSupportsFragmentsFromTheSupportV4Library() {
fromFragment(supportFragment, Observable.just("success")).subscribe(observer);
verify(observer).onNext("success");
verify(observer).onCompleted();
}

@Test
public void itSupportsNativeFragments() {
fromFragment(fragment, Observable.just("success")).subscribe(observer);
verify(observer).onNext("success");
verify(observer).onCompleted();
}

@Test(expected = IllegalArgumentException.class)
public void itThrowsIfObjectPassedIsNotAFragment() {
fromFragment("not a fragment", Observable.never());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,13 @@

import android.os.Handler;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

import rx.Scheduler;
import rx.Subscription;
import rx.operators.SafeObservableSubscription;
import rx.util.functions.Func2;

import java.util.concurrent.TimeUnit;

import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

/**
* Schedules actions to run on an Android Handler thread.
*/
Expand Down Expand Up @@ -84,49 +74,6 @@ public void run() {
}, unit.toMillis(delayTime));
return subscription;
}

@RunWith(RobolectricTestRunner.class)
@Config(manifest=Config.NONE)
public static final class UnitTest {

@Test
public void shouldScheduleImmediateActionOnHandlerThread() {
final Handler handler = mock(Handler.class);
final Object state = new Object();
@SuppressWarnings("unchecked")
final Func2<Scheduler, Object, Subscription> action = mock(Func2.class);

Scheduler scheduler = new HandlerThreadScheduler(handler);
scheduler.schedule(state, action);

// verify that we post to the given Handler
ArgumentCaptor<Runnable> runnable = ArgumentCaptor.forClass(Runnable.class);
verify(handler).postDelayed(runnable.capture(), eq(0L));

// verify that the given handler delegates to our action
runnable.getValue().run();
verify(action).call(scheduler, state);
}

@Test
public void shouldScheduleDelayedActionOnHandlerThread() {
final Handler handler = mock(Handler.class);
final Object state = new Object();
@SuppressWarnings("unchecked")
final Func2<Scheduler, Object, Subscription> action = mock(Func2.class);

Scheduler scheduler = new HandlerThreadScheduler(handler);
scheduler.schedule(state, action, 1L, TimeUnit.SECONDS);

// verify that we post to the given Handler
ArgumentCaptor<Runnable> runnable = ArgumentCaptor.forClass(Runnable.class);
verify(handler).postDelayed(runnable.capture(), eq(1000L));

// verify that the given handler delegates to our action
runnable.getValue().run();
verify(action).call(scheduler, state);
}
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,6 @@
*/
package rx.operators;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

import rx.Observable;
import rx.Observer;
import rx.Subscription;
Expand All @@ -42,7 +25,6 @@
import android.os.Looper;
import android.util.Log;

import java.lang.reflect.Field;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
Expand Down Expand Up @@ -164,150 +146,4 @@ protected boolean isComponentValid(android.support.v4.app.Fragment fragment) {
return fragment.isAdded();
}
}

@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public static final class UnitTest {

@Mock
private Observer<Integer> mockObserver;

@Mock
private Fragment mockFragment;

@Mock
private Activity mockActivity;

@Mock
private Observable<Integer> mockObservable;

@Before
public void setupMocks() {
MockitoAnnotations.initMocks(this);
when(mockFragment.isAdded()).thenReturn(true);
}

@Test
public void itThrowsIfObserverSubscribesFromBackgroundThread() throws Exception {
final Future<Object> future = Executors.newSingleThreadExecutor().submit(new Callable<Object>() {
@Override
public Object call() throws Exception {
OperationObserveFromAndroidComponent.observeFromAndroidComponent(
mockObservable, mockFragment).subscribe(mockObserver);
return null;
}
});
future.get(1, TimeUnit.SECONDS);
verify(mockObserver).onError(any(IllegalStateException.class));
verifyNoMoreInteractions(mockObserver);
}

@Test
public void itObservesTheSourceSequenceOnTheMainUIThread() {
OperationObserveFromAndroidComponent.observeFromAndroidComponent(mockObservable, mockFragment).subscribe(mockObserver);
verify(mockObservable).observeOn(AndroidSchedulers.mainThread());
}

@Test
public void itForwardsOnNextOnCompletedSequenceToTargetObserver() {
Observable<Integer> source = Observable.from(1, 2, 3);
OperationObserveFromAndroidComponent.observeFromAndroidComponent(source, mockFragment).subscribe(mockObserver);
verify(mockObserver, times(3)).onNext(anyInt());
verify(mockObserver).onCompleted();
verify(mockObserver, never()).onError(any(Exception.class));
}

@Test
public void itForwardsOnErrorToTargetObserver() {
final Exception exception = new Exception();
Observable<Integer> source = Observable.error(exception);
OperationObserveFromAndroidComponent.observeFromAndroidComponent(source, mockFragment).subscribe(mockObserver);
verify(mockObserver).onError(exception);
verify(mockObserver, never()).onNext(anyInt());
verify(mockObserver, never()).onCompleted();
}

@Test
public void itDropsOnNextOnCompletedSequenceIfTargetComponentIsGone() throws Throwable {
PublishSubject<Integer> source = PublishSubject.create();

final OnSubscribeFragment<Integer> operator = new OnSubscribeFragment<Integer>(source, mockFragment);
operator.onSubscribe(mockObserver);

source.onNext(1);
releaseComponentRef(operator);

source.onNext(2);
source.onNext(3);
source.onCompleted();

verify(mockObserver).onNext(1);
verifyNoMoreInteractions(mockObserver);
}

@Test
public void itDropsOnErrorIfTargetComponentIsGone() throws Throwable {
PublishSubject<Integer> source = PublishSubject.create();

final OnSubscribeFragment<Integer> operator = new OnSubscribeFragment<Integer>(source, mockFragment);
operator.onSubscribe(mockObserver);

source.onNext(1);
releaseComponentRef(operator);

source.onError(new Exception());

verify(mockObserver).onNext(1);
verifyNoMoreInteractions(mockObserver);
}

private void releaseComponentRef(OnSubscribeFragment<Integer> operator) throws NoSuchFieldException, IllegalAccessException {
final Field componentRef = operator.getClass().getSuperclass().getDeclaredField("componentRef");
componentRef.setAccessible(true);
componentRef.set(operator, null);
}

@Test
public void itDoesNotForwardOnNextOnCompletedSequenceIfFragmentIsDetached() {
PublishSubject<Integer> source = PublishSubject.create();
OperationObserveFromAndroidComponent.observeFromAndroidComponent(source, mockFragment).subscribe(mockObserver);

source.onNext(1);

when(mockFragment.isAdded()).thenReturn(false);
source.onNext(2);
source.onNext(3);
source.onCompleted();

verify(mockObserver).onNext(1);
verify(mockObserver, never()).onCompleted();
}

@Test
public void itDoesNotForwardOnErrorIfFragmentIsDetached() {
PublishSubject<Integer> source = PublishSubject.create();
OperationObserveFromAndroidComponent.observeFromAndroidComponent(source, mockFragment).subscribe(mockObserver);

source.onNext(1);

when(mockFragment.isAdded()).thenReturn(false);
source.onError(new Exception());

verify(mockObserver).onNext(1);
verify(mockObserver, never()).onError(any(Exception.class));
}

@Test
public void itUnsubscribesFromTheSourceSequence() {
Subscription underlying = mock(Subscription.class);
when(mockObservable.observeOn(AndroidSchedulers.mainThread())).thenReturn(mockObservable);
when(mockObservable.subscribe(any(Observer.class))).thenReturn(underlying);

Subscription sub = OperationObserveFromAndroidComponent.observeFromAndroidComponent(
mockObservable, mockActivity).subscribe(mockObserver);
sub.unsubscribe();

verify(underlying).unsubscribe();
}
}
}
Loading

0 comments on commit 7bae419

Please sign in to comment.