#java #spring-boot
Вопрос:
Я реализовал фильтр, который считывает тело ответа и подписывает его. Он использует обработчик ответов 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 amp; destroy override methods
}
Я хочу протестировать этот фильтр с помощью простого теста mockito. Однако издевательство не работает, так как оболочка 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
}
}
Цепочка mockfilter действительно работает в том смысле, что она записывает ответ, но на обертке написано «пусто»!
Фактическая реализация фильтра работает, поэтому я знаю, что этот обработчик содержимого работает отлично (если я позвоню почтальону в приложение с помощью этого реализованного фильтра). Но в простом тесте mockito он терпит неудачу. Поток fastbytearrayoutput в оболочке остается пустым. Как я могу написать ответ таким образом, чтобы его подхватила оболочка? Я не могу найти, как оболочка извлекает содержимое из ответа при выполнении chain.dofilter.
Заранее спасибо за любую помощь!
Стог
Ответ №1:
Что я обнаружил, что сработало для меня, так это расширение метода doFilter в классе MockFilterChain. Вот пример, который заполнит ваш ответ и обработчик содержимого.
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);
Комментарии:
1. Это хорошая идея, которую я еще не опробовал. Я попробую это сделать, может быть, позже на этой неделе. Мне пришлось двигаться дальше без решения, так как у меня некоторое время не было ответа, но я рассмотрю его, когда у меня будет для этого время.
2. Классно! Держите нас в курсе
3. Наконец-то у меня было время еще раз взглянуть на этот проект. И да, ваше решение сработало идеально! Большое спасибо.