简体   繁体   中英

ContentCachingResponseWrapper.getContentAsByteArray() is empty when testing with MockHttpServletResponse

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.

There are 2 things wrong with your code

  1. Your filter isn't wrapping the response in the ContentCachingResponseWrapper
  2. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM