JUnit测试Spring @Async void服务方法

我有一个Spring服务:

@Service @Transactional public class SomeService { @Async public void asyncMethod(Foo foo) { // processing takes significant time } } 

我对这个SomeService进行了集成测试:

 @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) @WebAppConfiguration @IntegrationTest @Transactional public class SomeServiceIntTest { @Inject private SomeService someService; @Test public void testAsyncMethod() { Foo testData = prepareTestData(); someService.asyncMethod(testData); verifyResults(); } // verifyResult() with assertions, etc. } 

这是问题所在:

  • 因为SomeService.asyncMethod(..)使用@Async和注释
  • 因为SpringJUnit4ClassRunner遵循@Async语义

testAsyncMethod线程将调用someService.asyncMethod(testData)调用到它自己的工作线程中,然后直接继续执行verifyResults() ,可能在前一个工作线程完成其工作之前。

在validation结果之前,如何等待someService.asyncMethod(testData)完成? 请注意, 如何使用Spring 4和注释编写unit testing来validation异步行为? 这里不适用,因为someService.asyncMethod(testData)返回void ,而不是Future

@Async语义, 一些活动的@Configuration类将具有@EnableAsync注释 ,例如

 @Configuration @EnableAsync @EnableScheduling public class AsyncConfiguration implements AsyncConfigurer { // } 

为了解决我的问题,我介绍了一个新的Spring配置文件non-async

如果non-async配置文件激活,则使用AsyncConfiguration

 @Configuration @EnableAsync @EnableScheduling @Profile("!non-async") public class AsyncConfiguration implements AsyncConfigurer { // this configuration will be active as long as profile "non-async" is not (!) active } 

如果非同步配置文件处于活动状态,则使用NonAsyncConfiguration

 @Configuration // notice the missing @EnableAsync annotation @EnableScheduling @Profile("non-async") public class NonAsyncConfiguration { // this configuration will be active as long as profile "non-async" is active } 

现在在有问题的JUnit测试类中,我显式激活“非异步”配置文件,以便相互排除异步行为:

 @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) @WebAppConfiguration @IntegrationTest @Transactional @ActiveProfiles(profiles = "non-async") public class SomeServiceIntTest { @Inject private SomeService someService; @Test public void testAsyncMethod() { Foo testData = prepareTestData(); someService.asyncMethod(testData); verifyResults(); } // verifyResult() with assertions, etc. } 

如果你正在使用Mockito(直接或通过Spring测试支持@MockBean ),它有一个validation模式,具有完全针对这种情况的超时: https : @MockBean /org/mockito/Mockito.html#22

 someAsyncCall(); verify(mock, timeout(100)).someMethod(); 

您也可以使用Awaitility(在互联网上找到它,没有尝试过)。 https://blog.jayway.com/2014/04/23/java-8-and-assertj-support-in-awaitility-1-6-0/

 someAsyncCall(); await().until( () -> assertThat(userRepo.size()).isEqualTo(1) ); 

如果您的方法返回CompletableFuture使用join方法 – 文档CompletableFuture :: join 。

此方法等待异步方法完成并返回结果。 在主线程中重新抛出任何遇到的exception。