问题
We have singleton controllers like
@Controller
class C {
@Autowire MyObject obj;
public void doGet() {
// do something with obj
}
}
MyObject is created in a filter/interceptor and is put into HttpServletRequest attributes. Then it's obtained in @Configuration:
@Configuration
class Config {
@Autowire
@Bean @Scope("request")
MyObject provideMyObject(HttpServletRequest req) {
return req.getAttribute("myObj");
}
}
Everything works well in main code, but not in testing: when I run it from an integration test:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/web-application-config_test.xml")
class MyTest {
@Autowired
C controller;
@Test
void test() {
// Here I can easily create "new MockHttpServletRequest()"
// and set MyObject to it, but how to make Spring know about it?
c.doGet();
}
}
it complains that NoSuchBeanDefinitionException: No matching bean of type [javax.servlet.http.HttpServletRequest]
. (At first, it complained about request scope is not active, but I resolved it using CustomScopeConfigurer with SimpleThreadScope as suggested here).
How to let Spring injection know about my MockHttpServletRequest? Or directly MyObject?
回答1:
Workarounded temporarily, but it looks like the right approach: in Config, instead of req.getAttribute("myObj")
, write
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
return (MyObject) requestAttributes.getAttribute("myObj", RequestAttributes.SCOPE_REQUEST);
so it does not need a HttpServletRequest instance anymore. And fill it in test:
MockHttpServletRequest request = new MockHttpServletRequest();
request.setAttribute("myObj", /* set up MyObject instance */)
RequestContextHolder.setRequestAttributes(new ServletWebRequest(request));
来源:https://stackoverflow.com/questions/17180417/spring-autowire-httpservletrequest-in-integration-tests