I have a filter for logging some information for each request to a Spring Boot application. Some of this information I need to extract from the body. That's not a problem in itself, but to do so I use ContentCachingResponseWrapper
, and that is messing up my unit tests.
Here is a simplified version of my filter:
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();
}
}
And here is a simplified version of my test:
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));
}
The problem is that when running my tests, wrappedResponse.getContentAsByteArray()
returns an empty array.
CodePudding user response:
There are 2 things wrong with your code
- Your filter isn't wrapping the response in the
ContentCachingResponseWrapper
- You are writing the response before the wrapping has occured on the underlying response, so the
ContentCachingResponseWrapper
has no change of caching the response.
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();
}
}
Now the response will be wrapped in the wrapper for responses written further down the FilterChain
. This is also something you can leverage in your testcase by mocking the FilterChain
and write the response in an answer.
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);
}
Something along these lines should do the trick.