I'm facing the same problem.
bilak's post gave the idea of having my custom AsyncUncaughtExceptionHandler
declared with a @Component
annotation.
Then, in my custom implmentation of AsyncConfigurer
I was injecting my custom AsyncUncaughtExceptionHandler
.
In my tests, I used the @MockBean
annotation on my custom AsyncUncaughtExceptionHandler
, so I was able to verify that the handleUncaughtException
was called with the appropriate exception.
Code sample:
AsyncExceptionHandler
@Slf4j
@Component
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
log.error("Exception while executing with message: {} ", throwable.getMessage());
log.error("Exception happen in {} method ", method.getName());
}
}
CustomAsyncConfigurer
@Configuration
public class CustomAsyncConfigurer implements AsyncConfigurer {
final private AsyncExceptionHandler asyncExceptionHandler;
@Autowired
public TaskExecutorConfiguration(AsyncExceptionHandler asyncExceptionHandler) {
this.asyncExceptionHandler = asyncExceptionHandler;
}
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(50);
executor.setThreadNamePrefix("AsyncThread::");
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return asyncExceptionHandler;
}
}
My unit test:
class FooServiceTest extends FooApplicationTests {
@MockBean
private AsyncExceptionHandler asyncExceptionHandler;
@Autowired
private FooService fooService;
@Test
void testCreateEnrollmentBioStoreException() throws Exception {
fooService.doBar();
ArgumentCaptor<FooException> argumentCaptor = ArgumentCaptor.forClass(FooException.class);
verify(asyncExceptionHandler, times(1)).handleUncaughtException(argumentCaptor.capture(), any(), any());
FooException exception = argumentCaptor.getValue();
assertEquals("Foo error message", exception.getMessage());
}
}
I'm not sure if this is the right way, but I have a void method that was turned into async, so I didn't want to change the return value just for the tests.