membersound
membersound

Reputation: 86925

How to test for Exception in @Async method?

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
   }
}

Upvotes: 3

Views: 1417

Answers (2)

Smaillns
Smaillns

Reputation: 3167

import static org.awaitility.Awaitility.await;

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

Upvotes: -1

embuc
embuc

Reputation: 688

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."

Upvotes: -1

Related Questions