Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxJava2: .andThen() called even though first Completable emitted error

I have 2 completables in a method, like:

completable1.doSomething()
    .andThen(completable2.doSomethingElse())

And I want to test it, by using Mockito and returning error in the first completable. Here is my original method:

 public Completable updateQuestion(Question question){
    return gameRepositoryType.updateQuestion(question)
            .andThen(gameRepositoryType.getGameById(question.getqId())
                    .map(GAME_MAPPER)
                    .flatMapCompletable(gameRepositoryType::updateGame))
            .observeOn(AndroidSchedulers.mainThread());
}

And here is my test:

@Test
public void updateQuestionError(){
    when(gameRepositoryType.updateQuestion(question)).thenReturn(Completable.error(error));
    when(question.getqId()).thenReturn(FAKE_QID);
    when(gameRepositoryType.getGameById(FAKE_QID)).thenReturn(Single.just(game));
    when(gameRepositoryType.updateGame(game)).thenReturn(Completable.complete());

    interactor.updateQuestion(question)
            .test()
            .assertNotComplete()
            .assertError(error);

    verify(gameRepositoryType).updateQuestion(question);       //this is called in test
    verify(question,never()).getqId();                         //this is called in test
    verify(gameRepositoryType,never()).getGameById(FAKE_QID);  //this is called in test
    verify(gameRepositoryType,never()).updateGame(game);       //this is NEVER called in test
}

In my verifications at the end of the test method, I am expecting after the first completable emitts an error, the 3 last verifications should run with success, i.e the 3 last verify() should never be called.

However I can see that all methods are called even though gameRepositoryType.updateQuestion(question) emitts error. Why is that?

Shouldn't andThen() never be called if the first completable emitts error?

like image 643
CJR Avatar asked Mar 03 '23 21:03

CJR


1 Answers

completable1.doSomething()
    .andThen(completable2.doSomethingElse())

Shouldn't andThen() never be called if the first completable emitts error?

andThen will always call completable2.doSomethingElse() to build the stream, but the Completable that is returned by it will never be subscribed to.

You can test it this way:

when(completable1.doSomething()).thenReturn(Completable.error(error));

CompletableSubject completableSubject = CompletableSubject.create();
when(completable2.doSomethingElse()).thenReturn(completableSubject);


TestObserver testObserver = completable1.doSomething()
    .andThen(completable2.doSomethingElse()).test();

// Verify that completable2.doSomethingElse() was never subscribed to:
assertFalse(completableSubject.hasObservers());

testObserver
    .assertError(error)
    .assertNotComplete();

Edit: for further clarification:

Given your methods are defined like this:

private Completable updateQuestion(Question question) {
    System.out.println("prints when the updateQuestion is called");
    return Completable.fromAction(() -> {
        System.out.println("prints when updateQuestion is subscribed to");
        database.updateQuestion(question);
    });
}

private Completable updateGame() {
    System.out.println("prints when the updateGame is called");
    return Completable.fromAction(() -> {
        System.out.println("prints when updateGame is subscribed to");
        database.updateGame();
    });
}

Suppose you call:

updateQuestion(question)
    .andThen(updateGame())
    .subscribe();

And database.updateQuestion(question); throws an error.

Then your log output would be:

prints when the updateQuestion is called
prints when the updateGame is called
prints when updateQuestion is subscribed to
>> error 

and database.updateGame(); will never be executed

like image 143
Gustavo Avatar answered Apr 25 '23 11:04

Gustavo