JUnit测试Spring @Async void服务方法

Abd*_*ull 22 java junit spring spring-async

我有一个Spring服务:

@Service
@Transactional
public class SomeService {

    @Async
    public void asyncMethod(Foo foo) {
        // processing takes significant time
    }
}
Run Code Online (Sandbox Code Playgroud)

我有一个集成测试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.
}
Run Code Online (Sandbox Code Playgroud)

这是问题所在:

  • 作为SomeService.asyncMethod(..)与注释@Async
  • 因为SpringJUnit4ClassRunner坚持@Async语义

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

someService.asyncMethod(testData)在验证结果之前,我该如何等待完成?请注意,如何使用Spring 4和注释编写单元测试来验证异步行为?不要在这里申请,作为someService.asyncMethod(testData)回报void,而不是Future<?>.

Abd*_*ull 21

对于@Async要遵守的语义,一些活动@Configuration类将具有@EnableAsync注释,例如

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

  //

}
Run Code Online (Sandbox Code Playgroud)

为解决我的问题,我介绍了一个新的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

}
Run Code Online (Sandbox Code Playgroud)

如果非异步轮廓活动的,则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

}
Run Code Online (Sandbox Code Playgroud)

现在在有问题的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.
}
Run Code Online (Sandbox Code Playgroud)


bas*_*iat 12

我已经通过注入 ThreadPoolTask​​Executor

进而

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

在验证结果之前,它如下:

  @Autowired
  private ThreadPoolTaskExecutor executor;

    @Test
    public void testAsyncMethod() {

        Foo testData = prepareTestData();

        someService.asyncMethod(testData);

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

        verifyResults();
    }
Run Code Online (Sandbox Code Playgroud)


jhy*_*yot 9

如果您使用的是Mockito(直接或通过Spring测试支持@MockBean),则它具有一个验证模式,具有针对这种情况的超时:https : //static.javadoc.io/org.mockito/mockito-core/2.10.0/org /mockito/Mockito.html#22

someAsyncCall();
verify(mock, timeout(100)).someMethod();
Run Code Online (Sandbox Code Playgroud)

您也可以使用Awaitility(在Internet上找到它,还没有尝试过)。 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) );
Run Code Online (Sandbox Code Playgroud)


Jan*_*res 5

如果您的方法返回CompletableFuture使用join方法 -文档 CompletableFuture::join

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