Java Spring测试集成测试中的自动连线HttpServletRequest
我试图做一个测试,以涵盖登录功能。Spring的版本是3.2.12。我有一个会话bean,声明为:Java Spring测试集成测试中的自动连线HttpServletRequest,java,spring,spring-mvc,spring-test,mockmvc,Java,Spring,Spring Mvc,Spring Test,Mockmvc,我试图做一个测试,以涵盖登录功能。Spring的版本是3.2.12。我有一个会话bean,声明为: @Service @Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES) public class ClientSessionServiceImpl implements ClientSessionService { @Autowired private HttpServletRequest request
@Service
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
public class ClientSessionServiceImpl implements ClientSessionService {
@Autowired
private HttpServletRequest request;
// This method is called during the login routine from the filter
public boolean checkUser() {
// I rely on request attributes here, which were set in the filter
}
当在服务器上运行时,这种方法可以很好地工作,但是当使用SpringTest方法运行时,问题就出现了。这是我的测试方法:
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).addFilter(springSecurityFilterChain).build();
mockMvc.perform(post(URL));
调试之后,我发现,当TestSpring上下文启动时
ServletTestExecutionListener.SetupRequestContextIf必要
创建了MockHttpServletRequest的实例,
MockHttpServletRequest=新的MockHttpServletRequest(mockServletContext);
//让我们把这个实例称为A。
这是一个到处都被注入的实例,我使用
@Autowired
HttpServletRequest request;
然而,调用MockMvc.perform会创建MockHttpServletRequest的另一个实例(我们称之为实例B),该实例会传递给所有筛选器、servlet等。因此,基本上,我在请求中的筛选器中设置的属性不能在ClientSessionServiceImpl中读取,因为MockHttpServletRequest的不同实例被注入其中
我花了很多时间在这上面,但仍然没有找到解决方案
附言。
我在StackOverflow中搜索过,有一些标题类似的问题,但描述的问题与我的不同,因为我不想将HttpServletRequest作为参数传递,而是希望它自动连接,除非有充分的理由。您可以使用它来交换在perform中创建的请求。您可以向测试中添加一个util方法,如
private static RequestPostProcessor mockedRequest(final MockHttpServletRequest mockHttpServletRequest) {
return new RequestPostProcessor() {
@Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
return mockHttpServletRequest;
}
};
}
您可以通过和
方法添加此后处理器来应用它
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).addFilter(springSecurityFilterChain).build();
mockMvc.perform(post(URL).with(mockedRequest(request)));
在这里,传递给mockedRequest
方法的request
将是包含所需属性的原始请求
因此,基本上,我在请求的过滤器中设置的属性不能
在ClientSessionServiceImpl中读取,因为
MockHttpServletRequest被注入其中
这是一个与Spring的RequestAttributes
何时填充到RequestContextHolder
中有关的时间问题。在生产环境中,我假设您正在配置RequestContextFilter
或RequestContextListener
在任何情况下,在测试中手动将RequestContextFilter
的实例添加到过滤器链的前端都可以解决问题
mockMvc=MockMvcBuilders
.webAppContextSetup(this.wac)
.addFilters(新建RequestContextFilter(),testFilterChain)
.build();
请注意,这将成为SpringFramework 4.2中的默认行为:模拟RequestContextFilter
的代码将直接在MockMvc
中实现。详情见JIRA问题
另外,不支持配置由
ServletTestExecutionListener
创建的MockHttpServletRequest
。如果您使用的是MockMvc
,则应通过RequestBuilders
配置模拟请求
但是,尽管如此,如果您确实需要手动修改由ServletTestExecutionListener
创建的模拟请求,然后将其与MockMvc
一起重新使用,那么您可以在项目中创建以下类:
包org.springframework.test.web.servlet.request;
导入javax.servlet.ServletContext;
导入javax.servlet.http.HttpServletRequest;
导入org.springframework.http.HttpMethod;
导入org.springframework.mock.web.MockHttpServletRequest;
导入org.springframework.web.context.request.RequestAttributes;
导入org.springframework.web.context.request.RequestContextHolder;
导入org.springframework.web.context.request.ServletRequestAttributes;
/**
*{@link MockHttpServletRequestBuilder}的修补版本。
*
*@作者萨姆·布兰宁
*@自4.2
*/
公共类PatchedMockHttpServletRequestBuilder扩展了MockHttpServletRequestBuilder{
公共静态MockHttpServletRequestBuilder获取(字符串urlTemplate、对象…urlVariables){
返回新的PatchedMockHttpServletRequestBuilder(HttpMethod.GET、urlTemplate、urlVariables);
}
公共补丁DockHttpServletRequestBuilder(HttpMethod HttpMethod、字符串urlTemplate、对象…urlVariables){
super(httpMethod、urlTemplate、urlVariables);
}
/**
*创建一个{@link MockHttpServletRequest}。
*如果{@code MockHttpServletRequest}的实例通过
*绑定到中当前线程的{@link RequestAttributes}
*{@link RequestContextHolder},此方法仅返回该实例。
*否则,此方法将创建一个新的{@code MockHttpServletRequest}
*基于提供的{@link ServletContext}。
*可以在子类中重写。
*@请参阅RequestContextHolder#getRequestAttributes()
*@请参阅ServletRequestAttributes
*/
@凌驾
受保护的MockHttpServletRequest createServletRequest(ServletContext ServletContext){
RequestAttributes RequestAttributes=RequestContextHolder.getRequestAttributes();
if(ServletRequestAttributes的requestAttributes实例){
HttpServletRequest请求=((ServletRequestAttributes)requestAttributes).getRequest();
if(MockHttpServletRequest的请求实例){
返回(MockHttpServletRequest)请求;
}
}
返回新的MockHttpServletRequest(servletContext);
}
}
注意:它必须在org.springframework.test.web.servlet.request
包中;否则,它无法扩展所需的MockHttpServletRequestBuilder
然后,使用PatchedMockHttpServletRequestBuilder
中的get()
方法,而不是使用MockMvcRequestBuilders
中的方法,一切都应该按照您的预期工作
显然,上面的示例重新实现了get()
,但是您自然可以对p执行同样的操作
@Autowired protected HttpServletRequest httpRequest;
@Autowired protected HttpServletResponse httpResponse;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("classpath:spring-config-unit-test.xml")
<bean class="org.springframework.mock.web.MockHttpServletRequest" name="httpRequest" lazy-init="false" />
<bean class="org.springframework.mock.web.MockHttpServletResponse" name="httpResponse" lazy-init="false" />
@RunWith(SpringJUnit4ClassRunner.class)
public class MyTests extends AbstractContextControllerTests {
@Test
public void test() {
}
}
@WebAppConfiguration
@ContextConfiguration(classes = {DispatcherConfig.class}, loader = AnnotationConfigWebContextLoader.class)
public class AbstractContextControllerTests {
@Autowired
protected WebApplicationContext wac;
}
@Configuration
@EnableWebMvc
public class DispatcherConfig extends WebMvcConfigurerAdapter {
}