How to test for Exception in @Async method?

Viewed 292

How can I assert that a certain exception is thrown inside an @Async method? Because the following exception is caught by Springs SimpleAsyncUncaughtExceptionHandler.

@Service
public class Service {
      @Async
      public void run() {
           throw new RuntimeException();
      }
}

public class Test {
   @Test
   public void test() {
        assertDoesNotThrow(() -> service.run()); //this always passes
   }
}
2 Answers

If it is possible for your case, separate testing of asynchronicity and the actual unit of work. E.g. write test that will execute (no 'Async' functionality) Service.run() and assert that no/any/some exceptions are thrown. In second test (utilizing @Async execution) you could test for the actual unit of work i.e. use your Spring provided bean and test for e.g.:

Awaitility.await().atMost(1000, TimeUnit.MILLISECONDS).untilAsserted(() -> runAnyCodeThatChecksTheResultOfYourServiceRunMethod());

Another method might be to replace the return type of the Service.run() method to java.util.concurrent.Future, Spring will then re-throw the exception. From AsyncExecutionAspectSupport.handleError javadoc:

"If the return type of the method is a {@link Future} object (again, if applicable), the original exception can be propagated by just throwing it at the higher level. However, for all other cases, the exception will not be transmitted back to the client."

import static org.awaitility.Awaitility.await;

Awaitility.await().atMost(5, TimeUnit.SECONDS)
  .untilAsserted(() -> assertThrows(RuntimeException.class, () ->  service.run()));
Related