用ContentCachingResponseWrapper mock来测试过滤器



我已经实现了一个过滤器,它读取响应体并对其签名。它使用ContentCachingResponseWrapper:

@Slf4j
public class ResponseSignerFilter extends AbstractSigner implements Filter {

public ResponseSignerFilter(....) {
//..constructor...
}
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
final ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(httpServletRequest);
final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
final ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(httpServletResponse);
chain.doFilter(requestWrapper, responseWrapper);
final boolean responseHasBody = responseWrapper.getContentSize() > 0;
if (responseHasBody) {
//use body to sign:
byte[] body = responseWrapper.getContentAsByteArray()
//...more code for the signing...
}
responseWrapper.copyBodyToResponse();
}
//init & destroy override methods
}

我想用一个简单的模拟测试测试这个过滤器。然而,mock不起作用,因为ContentCachingRequestWrapper将保持空。我尝试这样做:

@ExtendWith(MockitoExtension.class)
class ResponseSignerFilterTest {

@Test
void exampleTest() throws ServletException, IOException {
final ResponseSignerFilter filter = new ResponseSignerFilter(appPrivateKey, getJwtSettings());
final MockHttpServletRequest req = new MockHttpServletRequest();
req.setMethod("POST");
final MockHttpServletResponse res = new MockHttpServletResponse();
res.setContentType("application/json");
final byte[] someBodyBytes = "give some body".getBytes(StandardCharsets.UTF_8);
final MockFilterChain filterChain = new MockFilterChain(new HttpServlet() {
@Override
protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws IOException {
res.getWriter().write("test-body");
//alternative, does same thing:
// res.getOutputStream().write("test-body".getBytes(StandardCharsets.UTF_8));
res.setContentLength(5);
res.setCommitted(true);
}
});
filter.doFilter(req, res, filterChain);

//assertions on res
}
}

mockfilterchain确实工作,因为它写入响应,但包装器显示为空!

过滤器的实际实现工作,所以我知道这个contentCacheWrapper工作完美(如果我做一个邮递员调用这个过滤器实现的应用程序)。但在一个简单的模拟测试中,它失败了。包装器中的FastByteArrayOutputStream保持为空。我怎样才能以一种包装器能够接收的方式写入响应呢?我找不到包装器如何从响应时间链中获取内容。执行Dofilter

提前感谢您的帮助!

瑞克

我发现对我有效的是扩展doFilterMockFilterChain类。下面是一个示例,将填充您的响应和ContentCachingResponseWrapper.

private class FakeContentFilterChain extends MockFilterChain {
private byte[] responseContent;
FakeContentFilterChain(byte[] fakeContentToInject) {
this.responseContent = fakeContentToInject;
}
// Need to short-circuit the filter call chain to fake populate the response
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1)
throws IOException, ServletException {
if (arg1 instanceof HttpServletResponse) {
final HttpServletResponse httpServletResponse = (HttpServletResponse) arg1;
httpServletResponse.setStatus(HttpStatus.OK.value());
httpServletResponse.getOutputStream().write(responseContent);
}
}
}

那么你可以在你的代码中使用它:

FilterChain filterChain = new FakeContentFilterChain("test-body".getBytes());
filter.doFilter(req, res, filterChain);

最新更新