尝试使用MockHttpServletResponse测试ResponseHeaderFilter中的HttpServletResponseWrapper

时间:2012-02-06 15:58:20

标签: servlets junit servlet-filters cobertura

我正在尝试对下面的ResponseHeaderFilter进行单元测试,但发现此单元测试失败:

@Test
public void testDoFilterWithOmmissableInitParameters_ETag()
        throws IOException, ServletException {

    // Add allowableUserAgents initParameters
    MockFilterConfig filterConfig = new MockFilterConfig();
    filterConfig.addInitParameter("allowableUserAgents", "avaya");

    // Add allowableUserAgents initParameters
    filterConfig.addInitParameter(OMIT_KEY, OMIT_VALUE);

    // Set user-agent
    request.addHeader("user-agent", "avaya");
    response.addHeader("ETag", "someEtagHash");

    filter.init(filterConfig);
    filter.doFilter(request, response, chain);

    // THIS ASSERTION FAILS:
    assertThat((String)response.getHeader("ETag"), is(nullValue()));
}

具体来说,我在调试模式下运行它时的setHeader()方法永远不会被调用:

            chain.doFilter(request,
                                new HttpServletResponseWrapper(response) {
                                    public void setHeader(String name, String value) {
                                        //if (!(name != null && omitHeaders.contains(name.toUpperCase()))) {
                                        if (name != null && omitHeaders.contains(name)) {
                                            super.setHeader(name, value);
                                        }
                                    }
                                });

调试器到达新HttpServletResponseWrapper(响应)的行,但实际上并没有执行setHeader方法。

这是整个班级本身:

public class ResponseHeaderFilter implements Filter {

    private static final Logger logger = LoggerFactory.getLogger(ResponseHeaderFilter.class);

    Map<String, String> additionalHeaders = new HashMap<String, String>();

    Set<String> omitHeaders = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);

    Set<String> allowableUserAgents = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);

    boolean allowFromAllUserAgents = false;

    public void doFilter(final ServletRequest request,
                         final ServletResponse res,
                         final FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;

        String userAgent = ((HttpServletRequest) request).getHeader("user-agent");

        if (allowFromAllUserAgents
            || (userAgent != null && allowableUserAgents.contains(userAgent))
        ) {
            logger.debug("apply ResponseHeader rules for user agent [{}]", userAgent);
            for (Map.Entry<String, String> entry : additionalHeaders.entrySet()) {
                response.addHeader(entry.getKey(), entry.getValue());
            }

            chain.doFilter(request,
                                    new HttpServletResponseWrapper(response) {
                                        public void setHeader(String name, String value) {
                                            //if (!(name != null && omitHeaders.contains(name.toUpperCase()))) {
                                            if (name != null && omitHeaders.contains(name)) {
                                                super.setHeader(name, value);
                                            }
                                        }
                                    });
        } else {
            logger.debug("User agent [{}] is not an allowable agent for this filter", userAgent);
            chain.doFilter(request, res);
        }
    }

    /**
     * Called once during start-up
     *
     * @param filterConfig for Filter configuration
     */
    public void init(final FilterConfig filterConfig) {

        logger.info("*** ResponseHeaderFilter.init() ***");

        // set the provided HTTP response parameters
        for (Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements(); ) {
            String headerName = (String) e.nextElement();
            String headerValue = filterConfig.getInitParameter(headerName);

            // Add the list of allowable user-agents
            // cannot be null: if (headerName != null) {
                if (headerName.equalsIgnoreCase("allowableUserAgents")) {
                    // omit
                    parseToUpperCaseElements(headerValue, allowableUserAgents);
                    logger.debug("allowable user-agent's {}", allowableUserAgents);
                } else if (headerName.equalsIgnoreCase("allowFromAllUserAgents")) {
                    allowFromAllUserAgents = Boolean.parseBoolean(headerValue);
                    logger.debug("allowFromAllUserAgents {}", allowFromAllUserAgents);
                } else if (headerName.equalsIgnoreCase("omit")) {
                    parseToUpperCaseElements(headerValue, omitHeaders);
                    logger.debug("Omit headers {}", omitHeaders);
                } else {
                    additionalHeaders.put(headerName, headerValue);
                    logger.debug("adding header [{}] with value [{}]", headerName, headerValue);
                }
            //}
        }
    }

    protected final void parseToUpperCaseElements(final String str, final Set<String> elementKeys) {
        String[] words = str.split(",");
        for (String s : words) {
            elementKeys.add(s.trim().toUpperCase());
        }
    }

    public void destroy() {
        logger.debug("destroy");
    }
}

此过滤器在运行时实际上有效,并且删除了ETag标头,但是当我尝试使用Cobertura进行代码覆盖时,该方法未经过测试。

1 个答案:

答案 0 :(得分:0)

实际上,您正在测试ResponseHeaderFilter的代码只会在HttpServletResponseWrapper中添加或注册匿名FilterChain

chain.doFilter(request, new HttpServletResponseWrapper(response) {
    public void setHeader(String name, String value) { ... }
});

FilterChain由容器本身执行。您的测试代码除了传递FilterChain引用外什么都不做。

我不知道您的测试中FilterChain的真实类型,但是我没有断言标记被移除(assertThat((String)response.getHeader("ETag"), is(nullValue()));),而是将测试分成两个不同的测试。

  1. 将匿名HttpServletResponseWrapper替换为可以称为EtagRemoverHttpServletResponseWrapper的完整类型,并进行单元测试,实际上在wrapper.setHeader(...)上断言etag标题被省略。< / p>

  2. ResponseHeaderFilter上的第一个会断言chain包含ETagRemoverHttpServletResponseWrapper类型的引用

  3. 希望有所帮助。