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。