简体   繁体   中英

Testing CompletableFuture.supplyAsync with Mockito

I am trying to test CompletableFuture.supplyAsync function with mockito but the test is not completing probably because the completable future is not returning. I am not sure what I am missing in the code. Can anyone please help.

I have written the code as follows. So there are UserService class which returns User, UserEntityService class which returns users entities and a validation class to check if the entities belongs to the user or not.

I want to test if the passed entities belongs to user or not.

class UserService {

    CompletableFuture<User> getUser(String userName) {
        log.info("Fetching User with username {}", userName);
        return CompletableFuture.supplyAsync(
                () -> getUserByPortalUserName(userName));
    }
}
class UserEntityService {

    CompletableFuture<List<UserEntity>> getUserEntities(Long userId) {
        log.info("Retrieving all entities for user id {}", userId);
        return CompletableFuture.supplyAsync(
                () -> getAllByUserId(userId));
    }
}
class UserValidationService {

    public boolean validateUserCounterparty(UserRequest request) 
                   throws ExecutionException, InterruptedException {
        CompletableFuture<Boolean> result = userService.getUser(request.getUserName())
                .thenCompose(user -> userEntityService.getUserEntities(user.getUserId()))
                .thenCompose(userEntities -> validate(userEntities, request.getUserEntities()));

        Boolean validationStatus = result.get();
        if (!validationStatus) {
            log.error("Validation failed for user name {}", request.getUserName());
        }
        return validationStatus;
    }
}

And the test case is written as

@ExtendWith(MockitoExtension.class)
class UserValidationServiceTest {

    @Mock
    UserService userService;

    @Mock
    UserEntityService userEntityService;

    @InjectMocks
    UserValidationService userValidationService;

    @Before
    public void init() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void validateUser() throws ExecutionException, InterruptedException {
        CompletableFuture<User> userFuture = new CompletableFuture<>();
        CompletableFuture<List<UserEntity>> userEntityFuture = new CompletableFuture<>();

        Mockito.doReturn(userFuture).when(userService).getUser(anyString());
        Mockito.doReturn(userEntityFuture).when(userEntityService).getUserEntities(anyLong());

        UserRequest request = UserRequest.builder()
                .userName("admin")
                .userEntities(List.of("US", "ASIA", "EUROPE")).build();


        boolean result = validationService.validateUserCounterparty(request);
        assertTrue(result);

    }
}

On executing this test, it goes into infinite loop and never stops. I guess its because the completable future is not returning but I dont have enough knowledge on how to prevent it.

What modification should I do to prevent it?

In your test method you're creating CompletableFuture instances using new . JavaDoc states :

public CompletableFuture()

Creates a new incomplete CompletableFuture.

So the objects you're creating are never completing, that's why the test is running infinitely. It's not actually a loop, but waiting on a blocking operation to be finished, which never happens.

What you need to do is define a CompletableFuture that completes - immediately or after some time. The simplest way of doing that is by using the static completedFuture() method :

CompletableFuture<User> userFuture =
        CompletableFuture.completedFuture(new User());
CompletableFuture<List<UserEntity>> userEntityFuture =
        CompletableFuture.completedFuture(List.of(new UserEntity()));

Thanks to that given objects are returned and the code can be executed fully. You can test errors in a similar way by using the failedFuture() method .


I've created a GitHub repo with a minimal reproducible example - the test presented there passes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM