ContentCachingResponseWrapper.getContentAsByteArray() 在使用 MockHttpServletResponse 进行测试时为空
ContentCachingResponseWrapper.getContentAsByteArray() is empty when testing with MockHttpServletResponse
我有一个过滤器,用于将每个请求的一些信息记录到 Spring 启动应用程序。我需要从 body 中提取其中的一些信息。这本身不是问题,但为此我使用了 ContentCachingResponseWrapper
,这搞乱了我的单元测试。
这是我的过滤器的简化版本:
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
var wrappedResponse = response instanceof ContentCachingResponseWrapper ? (ContentCachingResponseWrapper) response : new ContentCachingResponseWrapper(response);
filterChain.doFilter(request, wrappedResponse);
} finally {
System.out.println("Response body: " + new String(wrappedResponse.getContentAsByteArray()));
wrappedResponse.copyBodyToResponse();
}
}
这是我测试的简化版本:
void myTest() throws ServletException, IOException {
final String body = "This is a body that my service might return.";
var testResp = new MockHttpServletResponse();
testResp.getWriter().print(body);
testResp.getWriter().flush();
testResp.setContentLength(body.length());
myFilter.doFilterInternal(Mockito.mock(HttpServletRequest.class), testResp, Mockito.mock(FilterChain.class));
}
问题是,当 运行 我的测试时,wrappedResponse.getContentAsByteArray()
returns 一个空数组。
您的代码有两处错误
- 您的过滤器没有将响应包装在
ContentCachingResponseWrapper
- 您在对基础响应进行包装之前编写响应,因此
ContentCachingResponseWrapper
没有更改缓存响应。
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
var wrappedResponse = response instanceof ContentCachingResponseWrapper ? (ContentCachingResponseWrapper) response : new ContentCachingResponseWrapper(response);
filterChain.doFilter(request, wrappedResponse);
} finally {
System.out.println("Response body: " + new String(wrappedResponse.getContentAsByteArray()));
wrappedResponse.copyBodyToResponse();
}
}
现在,响应将被包装在 FilterChain
后面写的响应的包装器中。这也是您可以通过模拟 FilterChain
并在答案中写入响应来在测试用例中利用的东西。
void myTest() throws ServletException, IOException {
var body = "This is a body that my service might return.";
var req = new MockHttpServletRequest();
var res = new MockHttpServletResponse();
var mockChain = Mockito.mock(FilterChain.class);
Mockito.when(mockChain.doFilter(any(), any())
.thenAnswer((it -> {
var response = it.getArgument(1, HttpServletResponse.class);
response.getWriter().print(body);
response.getWriter().flush();
response.setContentLength(body.length());
return null;
});
myFilter.doFilterInternal(req, res, mockChain);
}
按照这些思路应该可以解决问题。
我有一个过滤器,用于将每个请求的一些信息记录到 Spring 启动应用程序。我需要从 body 中提取其中的一些信息。这本身不是问题,但为此我使用了 ContentCachingResponseWrapper
,这搞乱了我的单元测试。
这是我的过滤器的简化版本:
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
var wrappedResponse = response instanceof ContentCachingResponseWrapper ? (ContentCachingResponseWrapper) response : new ContentCachingResponseWrapper(response);
filterChain.doFilter(request, wrappedResponse);
} finally {
System.out.println("Response body: " + new String(wrappedResponse.getContentAsByteArray()));
wrappedResponse.copyBodyToResponse();
}
}
这是我测试的简化版本:
void myTest() throws ServletException, IOException {
final String body = "This is a body that my service might return.";
var testResp = new MockHttpServletResponse();
testResp.getWriter().print(body);
testResp.getWriter().flush();
testResp.setContentLength(body.length());
myFilter.doFilterInternal(Mockito.mock(HttpServletRequest.class), testResp, Mockito.mock(FilterChain.class));
}
问题是,当 运行 我的测试时,wrappedResponse.getContentAsByteArray()
returns 一个空数组。
您的代码有两处错误
- 您的过滤器没有将响应包装在
ContentCachingResponseWrapper
- 您在对基础响应进行包装之前编写响应,因此
ContentCachingResponseWrapper
没有更改缓存响应。
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
var wrappedResponse = response instanceof ContentCachingResponseWrapper ? (ContentCachingResponseWrapper) response : new ContentCachingResponseWrapper(response);
filterChain.doFilter(request, wrappedResponse);
} finally {
System.out.println("Response body: " + new String(wrappedResponse.getContentAsByteArray()));
wrappedResponse.copyBodyToResponse();
}
}
现在,响应将被包装在 FilterChain
后面写的响应的包装器中。这也是您可以通过模拟 FilterChain
并在答案中写入响应来在测试用例中利用的东西。
void myTest() throws ServletException, IOException {
var body = "This is a body that my service might return.";
var req = new MockHttpServletRequest();
var res = new MockHttpServletResponse();
var mockChain = Mockito.mock(FilterChain.class);
Mockito.when(mockChain.doFilter(any(), any())
.thenAnswer((it -> {
var response = it.getArgument(1, HttpServletResponse.class);
response.getWriter().print(body);
response.getWriter().flush();
response.setContentLength(body.length());
return null;
});
myFilter.doFilterInternal(req, res, mockChain);
}
按照这些思路应该可以解决问题。