[英]Spring Boot integration testing with Async Jobs and Request Scope beans
我面临的问题包括3个因素:
该问题仅在测试中发生,而在不进行测试的情况下 ,应用程序将按预期运行。
简化的应用流程:
我在尝试运行Maven测试时遇到的错误:
org.springframework.beans.factory.BeanCreationException:创建名称为“ scopedTarget.requestBean”的bean时出错:当前线程的作用域“ request”未激活; 如果您打算从单例中引用它,请考虑为此bean定义作用域代理。 嵌套异常为java.lang.IllegalStateException:未找到线程绑定的请求:您是在实际Web请求之外引用请求属性,还是在原始接收线程之外处理请求? 如果您实际上是在Web请求中操作并且仍然收到此消息,则您的代码可能在DispatcherServlet / DispatcherPortlet之外运行:在这种情况下,请使用RequestContextListener或RequestContextFilter公开当前请求。
解决此问题的重要说明和线索 :当控制器直接从DAO(数据源)获取时,测试通过!!! 仅当它从Guava缓存中获取时才会失败。
简化代码:
/* Part of the controller: */
@Autowired AsyncCacheService cacheService;
@RequestMapping("/resellers")
public HashMap<String, Reseller> getAllResellers() throws Exception {
return cacheService.getAllResellers();
//When I switch to get directly from DAO below, tests pass.
//return partnerDao.getAllResellers(); <-- get directly from DAO.
}
/* The service which the controller calls */
@Service
public class AsyncCacheService {
private LoadingCache<String, List<Reseller>> resellersCache;
public AsyncCacheService() {
resellersCache = CacheBuilder.newBuilder().build(new CacheLoader<String,
HashMap<String, Reseller>>() {
public HashMap<String, Reseller> load(String key) throws Exception {
return partnerDao.getAllResellers();
}
});
}
@PostConstruct
private void refreshCache() {
/* Refresh cache concurrently */
Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(
() -> resellersCache.refresh(this.getClass().toString()), 0,
cacheRefreshTimeInterval, TimeUnit.SECONDS);
}
/* Return resellers from cache */
public HashMap<String, Reseller> getAllResellers() {
return resellersCache.getUnchecked(this.getClass().toString());
}
}
拦截器代码很简单:
@Component
public class AuthInterceptor extends HandlerInterceptorAdapter {
private @Autowired RequestBean requestBean;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) throws Exception {
//Verify request and requestBean.set(email, ip, foo)
}
}
我们如何实例化请求bean:
@Bean
@RequestScope
public RequestBean requestBean() {
return new RequestBean();
}
最后,测试:
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
tester {
@Test
public void allResellersSizeTest() throws Exception {
//MvcResult r =
mockMvc.perform(get("/api/resellers").header(authHeaderName, jwtToken))
.andExpect(status().isOk());//.andReturn();
}
}
我找不到适当的修复程序,因此我在服务器启动后延迟了几秒钟来延迟异步作业:
@PostConstruct
private void refreshCache() {
/* Refresh cache concurrently */
Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(
() -> resellersCache.refresh(this.getClass().toString()), 33,
cacheRefreshTimeInterval, TimeUnit.SECONDS);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.