Java JUnit 测试 Spring @Async void 服务方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42438862/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JUnit-testing a Spring @Async void service method
提问by Abdull
I have a Spring service:
我有一个 Spring 服务:
@Service
@Transactional
public class SomeService {
@Async
public void asyncMethod(Foo foo) {
// processing takes significant time
}
}
And I have an integration test for this SomeService:
我有一个集成测试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.
}
Here is the problem:
这是问题所在:
- as
SomeService.asyncMethod(..)is annotated with@Asyncand - as the
SpringJUnit4ClassRunneradheres to the@Asyncsemantics
- 如
SomeService.asyncMethod(..)标注有@Async和 - 因为
SpringJUnit4ClassRunner遵守@Async语义
the testAsyncMethodthread will fork the call someService.asyncMethod(testData)into its own worker thread, then directly continue executing verifyResults(), possibly before the previous worker thread has finished its work.
该testAsyncMethod线程将呼叫分叉someService.asyncMethod(testData)到自己的工作线程,然后直接继续执行verifyResults(),以前的工作线程完成其工作可能之前。
How can I wait for someService.asyncMethod(testData)'s completion before verifying the results? Notice that the solutions to How do I write a unit test to verify async behavior using Spring 4 and annotations?don't apply here, as someService.asyncMethod(testData)returns void, not a Future<?>.
someService.asyncMethod(testData)在验证结果之前如何等待's 完成?请注意如何使用 Spring 4 和注释编写单元测试来验证异步行为的解决方案?不要在这里申请,作为someService.asyncMethod(testData)返回void,而不是一个Future<?>。
采纳答案by Abdull
For @Asyncsemantics to be adhered, some active @Configurationclass will have the @EnableAsyncannotation, e.g.
为了@Async遵守语义,一些活动@Configuration类将具有@EnableAsync注释,例如
@Configuration
@EnableAsync
@EnableScheduling
public class AsyncConfiguration implements AsyncConfigurer {
//
}
To resolve my issue, I introduced a new Spring profile non-async.
为了解决我的问题,我引入了一个新的 Spring 配置文件non-async。
If the non-asyncprofile is notactive, the AsyncConfigurationis used:
如果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
}
If the non-async profile isactive, the NonAsyncConfigurationis used:
如果非异步轮廓是活动的,则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
}
Now in the problematic JUnit test class, I explicitly activate the "non-async" profile in order to mutually exclude the async behavior:
现在在有问题的 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.
}
回答by jhyot
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
如果您正在使用 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();
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/
你也可以使用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) );
回答by Jan Mares
In case your method returns CompletableFutureuse joinmethod - documentation CompletableFuture::join.
如果您的方法返回CompletableFuture使用join方法 -文档 CompletableFuture::join。
This method waits for the async method to finish and returns the result. Any encountered exception is rethrown in the main thread.
此方法等待异步方法完成并返回结果。任何遇到的异常都会在主线程中重新抛出。
回答by bastiat
I have done by injecting ThreadPoolTaskExecutor
我已经通过注入 ThreadPoolTaskExecutor
and then
进而
executor.getThreadPoolExecutor().awaitTermination(1, TimeUnit.SECONDS);
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();
}

