1
votes

In my application I am accessing my business objects using a Repository and RxJava. From my Presenter layer I can ask the Repository to get me ObjectA or get me ObjectB and the Respository will return an Observable or Observable respectively.

Sometimes I have the need to get both ObjectA and ObjectB. I'm wondering what the options are for fetching both objects using RxJava that also allows unit testing of my Presenter layer.

The way I originally implemented this was to use the flatMap() operator. So I'd do something like this:

//In Presenter layer
Observable<ObjectA> obsA = repository.getObjectA();
Observable<ObjectB> obsB = repository.getObjectB();

Observable<ObjectB> obsResult = obsA.flatMap(new Func1<ObjectA, Observable<ObjectB>>() {
@Override
public Observable<ObjectB> call(ObjectA a) {
    mObjectA = a;
    return obsB;
}
});

When I subscribe to the obsResult, obsA runs and I can access its result in the flatMap() operator. I get a handle to its result and store it as a field in my Presenter. Then obsB runs and I get its result in my Subscriber. This works just fine but I can't help but think I'm not really doing it right. One issue is that although I may have 100% test coverage in my Repository class, now I'm manipulating the observables that come out of the Repository class and I'm having a hard time figuring out how to test the obsResult or to verify that the code I write in flatMap() is correct.

Should I be adding methods to my Repository layer such as getObjectAandObjectB and return an Observable and do all of the work in the Repository layer? This would allow me to test the resultant Observable in the Repository layer tests rather than trying to create a new Observable from two separate Observables and figure out how to test it in my Presenter layer.

Another thing I've looked at is using the zip() operator. This would look something like this:

Observable<ObjectA> obsA = repository.getObjectA();
Observable<ObjectB> obsB = repository.getObjectB();

Observable<CombinedObjectAandObjectB> resultObs = obsA.zipWith(obsB, new Func2<ObjectA, ObjectB, CombinedObjectAandObjectB>() {
            @Override
            public Object call(ObjectA a, ObjectB b) {
                return new CombinedObjectAandObjectB(a,b);
            }
        });

Now when I subscribe to my resultObs I get a composite object returned with both ObjectA and Object B. This is pretty slick but still requires me to write code in Func2 that needs to be tested.

What are some ways that I can achieve my goals of combining calls for my business objects while also allowing for testability of the resultant Observable?

1

1 Answers

0
votes

You almost anwser your question yourself. According to Clean Architecture it's better to pass ready-to-use models to presentation layer. Combining logic belongs to Domain layer. So use zip() in your Repository (although it's Data layer). E.g.:

Observable.zip(modelAObservable, modelBOsbervable, (A, B) -> {
            combineModels(A, B);
        })...

private CombinedModel combineModels(modelA, modelB) {
    //combining logic
}

And test it as usual. E.g.:

ModelA A = new ModelA...
ModelB B = new ModelB...
CombinedModel expectedResult = new CombinedModel...

assertEquals(combineModels(A, B), expectedResult);