Reputation: 630
I want to do a sequence of operations. The next one can only execute if the previous was successful. To improve my understanding I decided to try to implement it with RxJava.
The operations, in order:
For this I use the following:
public interface LoginRepository {
Single<LoginResponseEntity> login(@NonNull final Credentials credentials);
Completable storeLoginResult(@NonNull final LoginResponseEntity loginEntity);
}
and
public interface UserSettingsRepository {
Single<UserInfoEntity> retrieveUserInfo(@NonNull final String email, final String accessToken);
Completable storeUserInfo(@NonNull final UserInfoEntity userInfoEntity);
}
and the Login usecase:
public Completable execute(@NonNull final Credentials credentials) {
return loginRepository.login(credentials)
.flatMap(loginEntity -> loginRepository.storeLoginResult(loginEntity)
.andThen(userSettingsRepository.retrieveUserInfo(credentials.getEmail(),
loginEntity.getAccessToken()))
).flatMapCompletable(userSettingsRepository::storeUserInfo)
.andThen(saveIsAlreadyLogged.execute());
}
So to test this, I have created unit tests (in Kotlin). All pass, except these two:
@Test
fun `when storing login result failed, don't retrieve user info`() {
val exception = Exception()
whenever(loginRepository.login(any())).thenReturn(Single.just(loginResponseEntity()))
whenever(loginRepository.storeLoginResult(any())).thenReturn(Completable.error(exception))
whenever(saveIsAlreadyLogged.execute()).thenReturn(Completable.complete())
val test = login.execute(credentials()).test()
verify(userSettingsRepository, never()).retrieveUserInfo(anyString(), anyString())
}
error:
org.mockito.exceptions.verification.NeverWantedButInvoked:
userSettingsRepository.retrieveUserInfo(
<any string>,
<any string>
);
and
@Test
fun `when storing login result failed, login should error`() {
val exception = Exception()
whenever(loginRepository.login(any())).thenReturn(Single.just(loginResponseEntity()))
whenever(loginRepository.storeLoginResult(any())).thenReturn(Completable.error(exception))
whenever(saveIsAlreadyLogged.execute()).thenReturn(Completable.complete())
val test = login.execute(credentials()).test()
test.assertError(exception)
}
error:
java.lang.AssertionError: Error not present (latch = 0, values = 0, errors = 1, completions = 0)
Do you know what I'm doing wrong? And do you have tips on how to improve my code? Please give a clear explanation as I'm still learning.
Upvotes: 0
Views: 1335
Reputation: 3606
For the first case, the problem is in:
.andThen(
userSettingsRepository.retrieveUserInfo(
credentials.getEmail(),
loginEntity.getAccessToken()
)
)
Note that the call to retrieveUserInfo
is done regardless of whatever happens to what you have before it. In other words: this is executed while your stream is being setup, and not when it's being run. You probably want to use Observable.defer
to inside the then
to match your expectations.
For the second problem, you can see that there IS an error happening:
java.lang.AssertionError: Error not present (latch = 0, values = 0, errors = 1, completions = 0)
errors = 1
is indicating that, and you'll need to look at the full message to see what the error is (as @akarnokd pointed out)
Upvotes: 1