0
votes

In my architecture I use a class called a UseCase to compose an observable and subscribe to it. The UseCase takes in one or more Repositories in the constructor and has an "execute" method that is responsible for creating the observable and subscribing to it.

Here's a simple example;

public class MyUseCase {
    IRepoA mRepoA;
    IRepoB mRepoB;
    Scheduler mScheduleOn;
    Scheduler mObserveOn;
    CompositeSubscription mCompositeSubscription;

    public MyUseCase(IRepoA repoA, IRepoB repoB, Scheduler subscribeOn, Scheduler observeOn, CompositeSubscription compositeSubscription) {
    mRepoA = repoA;
    mRepoB = repoB;
    mSubscribeOn = subscribeOn;
    mObserveOn = observeOn;
    mCompositeSubscription = compositeSubscription;
}

public Observable execute(Observable observable, Subscriber subscriber) {
    if (observable == null) {
                     observable = mRepoA
                    .fetchLoginPreference()
                    .map(new Func1<LoginPreference, String>() {
                        @Override
                        public String call(LoginPreference loginPreference) {
                            return loginPreference.getActivationCode();
                        }
                    })
                    .flatMap(new Func1<String, Observable<List<RegistrationField>>>() {
                        @Override
                        public Observable<List<RegistrationField>> call(String s) {
                            return mRepoB.fetchRegistrationFields(s);
                        }
                    })
    }
    mCompositeSubscription.add(observable.subscribeOn(mSubscribeOn).observeOn(mObserveOn).subscribe(observable));
    return observable;
}
}

It seems to me that there are a couple of things to test here and I'm wondering what the best way to go about it is.

1) I want to test that the observables are composed correctly. That is, I want to make sure that .map(), .flatMap(), and .cache() were called. The way I've done this before is to use mocks and verify that those methods were called on the mocks. So for instance, repoA.fetchLoginPreference() would return a mock observable and then I can verify that the mock has .map() called on it and so forth.

2) I want to test that the observable actually behaves correctly when I subscribe to it. To test this what I've done is to use real Observables instead of mocks. So when repoA.fetchLoginPreference() gets called I'd have it return Observable.just(mockLoginPreference). Then I use a TestSubscriber to subscribe to the resulting observable and verify that mocks are called correctly from within the Func1 callbacks.

Does this seem like a sane way of doing things? I end up being able to test both that the composition is correct and verify that when the observable is subscribed to it actually does what it's supposed to but I'm curious if there's a better way.

1

1 Answers

1
votes

Your first approach can be useful when you are learning the behavior of RxJava, especially with the more exotic operators, like switchMap(). However, you don't particularly need to test the correctness of the rxjava library itself.

The second approach makes a lot of sense. Having a unit test harness which is a combination of mocks and observable/test subscribers is a very powerful feature of reactive programming.

That being said, you may need both approaches when dealing with the CompositeSubscription() since I don't think it does what you think it does. Some low level debugging probes will be needed to ensure that operations get done on the threads