JUnit-testing a Spring @Async void service method

后端 未结 4 1647
情话喂你
情话喂你 2020-12-29 03:15

I have a Spring service:

@Service
@Transactional
public class SomeService {

    @Async
    public void asyncMethod(Foo foo) {
        // processing takes si         


        
相关标签:
4条回答
  • 2020-12-29 03:37

    In case your method returns CompletableFuture use join method - documentation CompletableFuture::join.

    This method waits for the async method to finish and returns the result. Any encountered exception is rethrown in the main thread.

    0 讨论(0)
  • 2020-12-29 03:39

    I have done by injecting ThreadPoolTaskExecutor

    and then

    executor.getThreadPoolExecutor().awaitTermination(1, TimeUnit.SECONDS);

    before verifying results, it as below:

      @Autowired
      private ThreadPoolTaskExecutor executor;
    
        @Test
        public void testAsyncMethod() {
    
            Foo testData = prepareTestData();
    
            someService.asyncMethod(testData);
    
            executor.getThreadPoolExecutor().awaitTermination(1, TimeUnit.SECONDS);
    
            verifyResults();
        }
    
    0 讨论(0)
  • 2020-12-29 03:42

    For @Async semantics to be adhered, some active @Configuration class will have the @EnableAsync annotation, e.g.

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

    To resolve my issue, I introduced a new Spring profile non-async.

    If the non-async profile is not active, the AsyncConfiguration is used:

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

    If the non-async profile is active, the NonAsyncConfiguration is used:

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

    Now in the problematic JUnit test class, I explicitly activate the "non-async" profile in order to mutually exclude the async behavior:

    @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.
    }
    
    0 讨论(0)
  • 2020-12-29 03:45

    If you are using Mockito (directly or via Spring testing support @MockBean), it has a verification mode with a timeout exactly for this case: https://static.javadoc.io/org.mockito/mockito-core/2.10.0/org/mockito/Mockito.html#22

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

    You could also use Awaitility (found it on the internet, haven't tried it). 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 讨论(0)
提交回复
热议问题