2017-02-24 59 views
6

我有一个春季服务:的JUnit测试春天@Async无效服务方法

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

这里的问题是:

  • as SomeService.asyncMethod(..)@Async
  • 注释
  • SpringJUnit4ClassRunner粘附在@Async语义

testAsyncMethod线程将呼叫分叉someService.asyncMethod(testData)到自己的工作线程,然后直接继续执行verifyResults(),以前的工作线程完成其工作可能之前。

在验证结果之前,我如何等待someService.asyncMethod(testData)完成?请注意,How do I write a unit test to verify async behavior using Spring 4 and annotations?的解决方案在此不适用,因为someService.asyncMethod(testData)返回void,而不是Future<?>

回答

8

对于@Async要遵守的语义,some active @Configuration class will have the @EnableAsync annotation,例如,

@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. 
} 
1

如果您正在使用的Mockito(直接或通过弹簧试验支持@MockBean),它与恰好为这种情况下超时验证模式: https://static.javadoc.io/org.mockito/mockito-core/2.10.0/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)); 
0

如果你的方法返回CompletableFuture使用join方法 - documentation CompletableFuture::join

此方法等待异步方法完成并返回结果。任何遇到的异常都会在主线程中重新生成。