Issue
I have some code that returns Mono<List<UserObject>>
. The first thing I want to do is check the List is not empty, and if it is, throw a NoUsersFoundException
. My code looks like this:
IUserDao.java
Mono<List<UserAccount>> getUserProfiles(final Set<UserQueryFilter> filters,
final Set<String> attributes);
GetUserAccount.java
public Mono<UserAccount> doGetUserAccount() {
return userDao.getUserProfiles(filters, attributes)
.map(list -> {
if (CollectionUtils.isEmpty(list)) {
throw new NoUsersFoundException();
}
return list;
})
.map(this::removePermissions)
.map(this::removeDuplicates);
}
I want to write a unit test that will test that the NoUsersFoundException
is thrown when userDao.getUserProfiles(filters, attributes)
returns an empty list. When I use Mockito#when
with a .thenReturn()
, the test will, as expected, return immediately once userDao.getUserProfiles(...)
is called without continuing the flow into the .map()
where the list is checked and exception thrown.
@Mock
private IUserDao userDao;
private UserPolicies userPolicies;
@BeforeEach
public void init() {
userPolicies = new UserPolicies(Set.of("XYZ", USER_AFF, "123"),
Set.of(TestUserConstants.ID, TestUserConstants.SUBSCRIPTION_LEVEL));
}
@Test
void shouldThrowExceptionIfNoUsersFound() {
final Set<UserFilter> filters = new UserFilterBuilder().withId(ID)
.withSubscription(PREMIUM)
.build();
when(userDao.getUserProfiles(filters, userPolicies.getUserAttributeIds()))
.thenReturn(Mono.just(Collections.emptyList()));
testClass = new GetUserAccount(userDao,
userPolicies,
filters,
userPolicies.getUserAttributeIds());
assertThatThrownBy(() -> testClass.doGetUserAccount()).isInstanceOf(NoUsersFoundException.class);
}
I have tried .thenAnswer()
but it essentially does the same thing as the method called is not a void:
userDao.getUserProfiles(filters, userPolicies.getUserAttributeIds()))
.thenAnswer((Answer<Mono<List>>) invocationOnMock -> Mono.just(Collections.emptyList()));
I can't see how using reactor.test.StepVerifier
would work for this case.
Solution
i dont really understand what you are asking for, but we commonly dont "throw" exceptions in reactor. We return a Mono#error
downstream, and different operators will react accordingly as the error travels downstream.
public Mono<List<Foobar> fooBar(filters, attributes) {
return daoObject.getUserProfiles(filters, attributes)
.map(list -> {
if (CollectionUtils.isEmpty(list)) {
// Return a mono#error
return Mono.error( ... );
}
return list;
})
}
And then test using the step verifier. With either expectNext
or expectError
.
// Happy case
StepVerifier.create(
fooBar(filters, attributes))
.expectNext( ... )
.verify();
// Sad case
StepVerifier.create(
fooBar(filters, attributes))
.expectError( ... )
.verify();
Answered By - Toerktumlare
Answer Checked By - Candace Johnson (JavaFixing Volunteer)