使用响应包装器使用Mockito测试ServletFilter

时间:2017-03-17 10:49:09

标签: java filter mockito

我正在尝试为我编写的过滤器编写单元测试。这听起来很简单,但有一点我无法弄清楚哪个是设置ServletResponse的状态代码。不幸的是,这很复杂,因为我正在使用HttpServletResponseWrapper,因为我需要检查响应状态代码(因为我需要覆盖它并返回200)。作为参考,我得到一个IncludedResponse,它有一个getStatusCode(),但由于某种原因在JDK源中它返回0?!?无论如何,这是我所拥有的过滤器的一部分:

private void handleUploadFilePost(ServletResponse servletResponse, HttpServletResponse httpServletResponse,
    HttpServletRequest httpServletRequest, FilterChain filterChain) throws IOException, ServletException {
    RequestWrapper requestWrapper = new RequestWrapper(httpServletRequest);
    ResponseWrapper responseWrapper = new ResponseWrapper(httpServletResponse);
    String requestBodyTrimmed = getRequestBody(requestWrapper.getInputStream());
    Case caseDetails = requestBodyMappingHelper.mapRequestBody(requestBodyTrimmed, Case.class);
    filterChain.doFilter(requestWrapper, responseWrapper);
    if (responseWrapper.getStatus() >= 400 && responseWrapper.getStatus() <= 599) {
        ...
    }
}

不幸的是,这会在测试时产生问题。如果它是一个简单的ServletResponse我嘲笑它并做...

when(myServletResponse).getStatus().thenReturn(...)

但是,因为我正在为状态创建自定义包装器,所以它似乎无法设置此局部变量的状态代码,因为它在包装器中保存为int,它覆盖了HttpServletResponse setStatus。

因此,我可以使用Mockito或Powermock做我想做的事吗?设置HttpServletResponse值后,它会覆盖它并将状态存储在我的包装器中,但我无法使其工作。我已经尝试了以下内容:

doAnswer(new Answer() {
    public Object answer(InvocationOnMock invocation) {
        servletResponse.setStatus(400);
        return null; // void method, so return null
    }
}).when(filterChain).doFilter(Mockito.any(ServletRequest.class), Mockito.any(ServletResponse.class));

但由于某些原因,这不起作用。测试中的ServletResponse没有被模拟,我实际上正在创建它,以便触发它的setStatus(),它将被Wrapper截获;

private IncludedResponse servletResponse;

servletResponse = new IncludedResponse();
servletResponse.setProxiedHttpServletResponse(new IncludedResponse());

非常感谢您提供的任何帮助。

非常感谢

2 个答案:

答案 0 :(得分:1)

  

当(myServletResponse).getStatus()。thenReturn(...)

正确的是

当(myServletResponse.getStatus()的 .thenReturn(...)

或更改为更一般的形式:

doReturn(...).when(myServletResponse).getStatus()

还允许对void方法进行trowing异常:

doThrow(new *Exception())when(mock).veoidMethod();
  

我也不能这样做(doReturn)部分,因为我如何将包装器模拟为局部变量。这就是我需要设置原始ServletResponse.setStatus方法

的原因

如果要应用依赖注入,则可以轻松使用本地模拟。

答案 1 :(得分:0)

不知道为什么我之前没想过这个。我能做的是创建我自己的过滤器链:

FilterChain filterChain = new FilterChain() {
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse)
        throws IOException, ServletException {
        if (servletResponse instanceof HttpServletResponse) {
            ((HttpServletResponse) servletResponse).setStatus(400);
        }
    }
};

这样当响应回来时,我不需要模拟它或其他任何东西,但我实际上得到了包装器使用的响应对象。比尝试使用模拟更容易(如果有可能的话)。

感谢蒂莫西的评论。我会留下这个,以防其他人像我一样有脑块!