I want to test a method which asynchronously calls an API. Somewhat like below -
private void callExternalAPI(){
CompletableFuture.runAsync(() -> {
try{
//Calling the API
}catch(final Exception e){
//logging some metrics
}
});
}
I am mocking the API call in the tests, returning some values of throwing some exceptions to test both the success case and exception case and verifying metrics. Using JUnit & Mockito to write tests.
The test completes its execution before the asynchronous part could complete logging the metric and the test could catch them, which gives me a
Argument(s) are different, Wanted: Error
When I remove the CompletableFuture.runAsync part and make the code Synchronous, then the tests pass.
I tried multiple things like -
- Thread.sleep(5000) just after the test subject was called.
- In the verify(), I used timeout(5000) like below -
verify(mockMetricLogger, timeout(5000).times(1)).....
I did not want to use Awaitility or Executors, they would unnecessarily make the code big.
Also, don't want to use supplyAsync or return anything from this method.
runAsyncmethod.callExternalAPI()can not be sure that the operation has been performed nor know whether it was successful or not. When you’re fine with that, there’s no point in testing that method which is just a wrapper around the actual operation. If you think the actual operation is worth testing, it’s also worth being in a named method rather than an anonymous lambda expression. Move it into a method, changecallExternalAPI()toCompletableFuture.runAsync(this::theNewMethod)and create a unit test fortheNewMethod()instead.