我有一个 Spring 服务:
@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)
返回void
,而不是Future<?>
。 最佳答案
为了遵守@Async
语义,some active @Configuration
class will have the @EnableAsync
annotation例如
@Configuration
@EnableAsync
@EnableScheduling
public class AsyncConfiguration implements AsyncConfigurer {
//
}
为了解决我的问题,我引入了一个新的Spring配置文件
non-async
。如果
non-async
配置文件是而不是处于 Activity 状态,则使用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
}
如果非异步配置文件是处于 Activity 状态,则使用
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.
}