2017-02-24 7 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. 
} 

は問題です:

  • としては、@Async
  • と注釈されている
  • SpringJUnit4ClassRunner@Asyncセマンティクス

testAsyncMethodスレッドへの付着としては、直接、前のワーカースレッドが作業を終えた、おそらく前に、verifyResults()を実行し続ける、独自のワーカースレッドに呼び出しsomeService.asyncMethod(testData)をforkします。

結果を確認する前にsomeService.asyncMethod(testData)の完了を待つことができますか? someService.asyncMethod(testData)voidを返し、Future<?>を返さないので、How do I write a unit test to verify async behavior using Spring 4 and annotations?の解はここでは適用されないことに注意してください。

答えて

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を。

このメソッドは、非同期メソッドが完了するのを待って結果を返します。すべての発生した例外は、メインスレッドで再スローされます。

関連する問題