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

यहाँ समस्या है:

  • 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) देता है, Future<?> नहीं।

उत्तर

8

@Async के लिए अर्थशास्त्र का पालन किया जाना चाहिए, some active @Configuration class will have the @EnableAsync annotation, उदा।

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

    // 

} 

मेरी समस्या को हल करने के लिए, मैंने एक नया वसंत प्रोफ़ाइल 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 

} 

यदि गैर-async प्रोफ़ाइल सक्रिय है, 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 

} 

अब समस्याग्रस्त जुनीट टेस्ट क्लास में, मैं एसिंक व्यवहार को पारस्परिक रूप से बहिष्कृत करने के लिए स्पष्ट रूप से "non-async" प्रोफ़ाइल को सक्रिय करता हूं:

@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

यह विधि एसिंक विधि को समाप्त करने और परिणाम देने के लिए प्रतीक्षा करती है। किसी भी सामना का अपवाद मुख्य धागे में पुनर्स्थापित किया जाता है।

संबंधित मुद्दे