如何对具有特定响应的Servlet过滤器进行Junit测试

3
什么是最佳的单元测试方法?我需要建立一个一致的检查httpResponse的方式,当条件为true时发送错误。谢谢!
编辑:不幸的是,这个过滤器不是使用Spring MVC的,所以我的选择很有限。
    public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain filterchain) throws IOException, ServletException {

    String ipAddress = request.getRemoteAddr();
    if( SomeParameterCheckingFunction ((request)) ) {
        logger.error("Error detected! Time: " + new Date().toString() + ", Originating IP: " + ipAddress);
        if (response instanceof HttpServletResponse){
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN,"You are not allowed to access the server!");
        }
    }
    filterchain.doFilter(request, response);
}
3个回答

7
例如,当使用Mockito模拟框架时,提供的doFilter()方法可以使用以下测试用例进行JUnit测试:
@Test
public void testDoFilter() throws IOException, ServletException {
    // create the objects to be mocked
    HttpServletRequest httpServletRequest = mock(HttpServletRequest.class);
    HttpServletResponse httpServletResponse = mock(HttpServletResponse.class);
    FilterChain filterChain = mock(FilterChain.class);
    // mock the getRemoteAddr() response
    when(httpServletRequest.getRemoteAddr()).thenReturn("198.252.206.16");

    AccessFilter accessFilter = new AccessFilter();
    accessFilter.doFilter(httpServletRequest, httpServletResponse,
            filterChain);

    // verify if a sendError() was performed with the expected values
    verify(httpServletResponse).sendError(HttpServletResponse.SC_FORBIDDEN,
            "You are not allowed to access the server!");
}

为什么你要嘲笑 getRemoteAddr()。看起来这并不必要。 - Adam Johns

0

一种选择可能是将SomeParameterCheckingFunction的定义从过滤器本身中提取出来(并在过滤器中使用它)。然后,您可以单独对该逻辑进行单元测试。但是,我不确定这对您是否足够。

另一种选择可能是使用Mockito测试过滤器类。这将涉及一些工作,模拟请求、响应、filterchain、日志记录等。之后,您应该能够验证response.sendError()调用,如下所示(假定静态导入Mockito.*方法):

//setup mock with concrete class for instanceof check
ServletResponse resp = mock(HttpServletResponse.class);

//define behavior for desired method with void return type.  this appears optional for mocks.
//doNothing().when(resp).sendError(anyInt(), anyString());

//your test here, passing in resp       
if(resp instanceof HttpServletResponse) resp.sendError(400, "blah");

//verify method was called      
verify(resp).sendError(400, "blah");

使用HttpUnit可能存在一种测试你的过滤器的方式,但这可能无法满足你对于一个合适单元测试的需求。


我已经有了另一个针对SomeParameterCheckingFunction()的单元测试,因此我可以轻松地使用Mockito进行模拟。能够验证response.sendError()将是一个理想的测试用例,但我完全不知道如何做到这一点。你能向我展示在过滤器被调用后如何在junit中验证response.sendError()的技巧吗?谢谢! - hb5fa

0

2018年2月更新:OpenBrace有限公司已关闭,其ObMimic产品不再受支持。

以下是使用我编写的ObMimic库进行“sendError”测试的示例,该库是用于Servlet API的容器外测试替身。

首先,关于给定的doFilter代码的一些说明:

  • "((request))" 可能只是指 "(request)"。

  • 由于 "logger" 的性质没有显示,因此我暂时将其视为不相关的。

  • 所给的过滤器将检查非 HTTP 请求,但如果它们被拒绝,则会写入通常的日志消息,但然后跳过 sendError 并执行正常处理。根据您想要做什么,您可能希望预先拒绝非 HTTP 请求,或者根本不检查它们,或者在 "sendError" 的位置进行某种其他类型的拒绝。现在,我假设我们只对如何测试 HTTP 请求中的 "sendError" 感兴趣。

  • 下面的示例测试表明,即使调用了 sendError,处理仍将放弃到正常的 "doFilter" 调用。假设这不是故意的,那么 "sendError" 应该后跟一个 "return",或者 "doFilter" 应该在一个 "else" 子句中。

对于下面的示例代码:

  • 我使用了JUnit作为测试框架,但也可以使用TestNG或其他任何框架。

  • 对于"SomeParameterCheckingFunction",我只是使用了一个返回true的函数,如果远程IP地址是"1.1.1.1"。

  • "sendError"会生成一个显示给定消息的HTML响应。在这个例子中,我只是检查响应正文是否包含给定的消息。如果你想要检查传递给"sendError"的参数值,ObMimic的"Professional Edition"有一个"history"功能可以让你做到这一点。或者你可以在一个单独的响应实例上执行"sendError",然后检查响应正文是否完全匹配。

无论如何,这是示例代码:

package com.openbrace.experiments.examplecode.stackoverflow13365536;

import static org.junit.Assert.*;
import com.openbrace.experiments.examplecode.stackoverflow13365536.YourFilter;
import com.openbrace.obmimic.mimic.servlet.FilterChainMimic;
import com.openbrace.obmimic.mimic.servlet.FilterConfigMimic;
import com.openbrace.obmimic.mimic.servlet.ServletMimic;
import com.openbrace.obmimic.mimic.servlet.http.HttpServletRequestMimic;
import com.openbrace.obmimic.mimic.servlet.http.HttpServletResponseMimic;
import com.openbrace.obmimic.support.servlet.EndPoint;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Example tests for {@link YourFilter#doFilter(ServletRequest, ServletResponse,
 * FilterChain)}.
 *
 * @author Mike Kaufman, OpenBrace Limited
 */
public class YourFilterTest {

    /** The filter to be tested by this instance's test. */
    private YourFilter filter;

    /** The "mimic" request to be used in this instance's test. */
    private HttpServletRequestMimic request;

    /** The "mimic" response to be used in this instance's test. */
    private HttpServletResponseMimic response;

    /** The filter chain to be used in this instance's test. */
    private FilterChainMimic filterChain;

    /**
     * Set up for this instance's test by creating an initialized filter and a
     * request, response and filter chain for use in the test.
     *
     * @throws ServletException if the filter's init method throws such an
     *     exception.
     */
    @Before
    public void setUp() throws ServletException {
        /*
         * Note that for this example's simple filter and tests:
         * - We don't need anything particular in the filter's FilterConfig.
         * - We don't need any particular ServletContext, so we can leave
         *   ObMimic to use its default ServletContext throughout.
         * - We don't need to retain any references to the filter's FilterConfig
         *   or ServletContext.
         * - We can use a FilterChainMimic with default values as the filter
         *   chain. This has a ServletMimic as the next thing in the chain, and
         *   ServletMimic keeps a count of the calls to its service method, so
         *   we can use this to check whether the filter chain's doFilter has
         *   been invoked.
         */
        filter = new YourFilter();
        filter.init(new FilterConfigMimic());
        request = new HttpServletRequestMimic();
        response = new HttpServletResponseMimic();
        filterChain = new FilterChainMimic();
    }

    /**
     * Test the doFilter method with an example request for which
     * SomeParameterCheckingFunction returns true (so that the FORBIDDEN
     * response should result).
     *
     * @throws ServletException if the servlet throws such an exception.
     * @throws IOException if the servlet throws such an exception.
     */
    @Test
    public void testYourFilterWithForbiddenRequest()
            throws ServletException, IOException {

        // Configure the request so that SomeParameterCheckingFunction will
        // return true, which for purposes of this example is triggered by a
        // particular "remote address".
        request.getMimicState().setRemoteEndPoint(
            new EndPoint(null, "1.1.1.1", null));

        // Invoke the doFilter method.
        filter.doFilter(request, response, filterChain);

        // Check that the response is now FORBIDDEN, and that its HTML content
        // does include the expected text message.
        int responseCode = response.getMimicState().getHttpStatusCode();
        String responseBody = response.getMimicState().getBodyContentAsString();
        String expectedMessage = "You are not allowed to access the server!";
        assertEquals("Response has incorrect status code",
            HttpServletResponse.SC_FORBIDDEN, responseCode);
        Assert.assertThat("FORBIDDEN response does not include expected message",
            responseBody, CoreMatchers.containsString(expectedMessage));

        // Check that the filter chain was not invoked. As we've used a
        // FilterChainMimic with default values, its "target" is a ServletMimic,
        // so we can just check if there have been any calls to that Servlet.
        ServletMimic targetServlet
            = (ServletMimic) filterChain.getMimicState().getTarget();
        boolean filterChainInvoked
            = targetServlet.getMimicState().getServiceCount() > 0;
        assertFalse("FORBIDDEN response but filterChain.doFilter still called",
            filterChainInvoked);

    }

}

如果你想尝试一下,可以在ObMimic网站上找到ObMimic的详细信息和免费下载。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接