【问题标题】:Unit Testing doFilter for Correlation Id相关 ID 的单元测试 doFilter
【发布时间】:2018-10-07 01:13:04
【问题描述】:

我正在使用 dropwizard 构建应用程序。

我做了一个过滤器来拦截和记录调用服务的相关ID。

如果传入请求的标头中没有标头“Correlation-Id”,我们会在响应中附加一个标头。

以下是过滤器:

public class CorrelationIdServletFilter implements Filter {

private static final Logger LOGGER =
  LoggerFactory.getLogger(CorrelationIdServletFilter.class);

 private static final String CORRELATION_ID_HEADER_NAME = "Correlation-ID";

 private static final String CORRELATION_ID_MDC_KEY = " ";

 private static final InheritableThreadLocal<String> correlationId =
  new InheritableThreadLocal<>();

  public static String getCorrelationId() {
return correlationId.get();
 }

 @Override
 public void init(FilterConfig filterConfig) throws ServletException {}

 @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  throws IOException, ServletException {

try {
  HttpServletRequest req = (HttpServletRequest) request;

  HttpServletResponse res = (HttpServletResponse) response;

  String correlationIdHeaderValue = req.getHeader(CORRELATION_ID_HEADER_NAME);

  LOGGER.debug
      (
      "HTTP Header("
          + CORRELATION_ID_HEADER_NAME
          + ") = ["
          + correlationIdHeaderValue
          + "] will generate a new correlationId if incoming is NULL");

  String correlationIdRaw;

  if (!StringUtils.isEmpty(correlationIdHeaderValue)) {
    correlationIdRaw = correlationIdHeaderValue;
  } else {
    correlationIdRaw = UUID.randomUUID().toString();
  }

  LOGGER.debug("Request: (" + req.getRequestURI() + ") is marked as :" + correlationIdRaw);

  correlationId.set(correlationIdRaw);

  MDC.put(CORRELATION_ID_MDC_KEY, getCorrelationId());

  res.addHeader(CORRELATION_ID_HEADER_NAME, correlationIdRaw);

  LOGGER.debug(
      "Response holds correlationId : ("
          + res.getHeader("Correlation-ID")
          + ") in its header ");

  chain.doFilter(req, res);

} finally {
  correlationId.remove();
  MDC.remove(CORRELATION_ID_MDC_KEY);
}
}

  @Override
  public void destroy() {}
}

我需要编写单元测试来涵盖两种情况:

  1. 发送请求时没有关联 ID。检查在服务器端生成的 id。

  2. 发送带有相关 ID 的响应时。检查它是否与响应一起发回。

谁能指点我这是怎么做到的?

我尝试使用模拟,但我不是响应,标题中没有任何内容。

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

HttpServletRequest httpServletRequest = mock(HttpServletRequest.class);
HttpServletResponse httpServletResponse = mock(HttpServletResponse.class);
FilterChain filterChain = mock(FilterChain.class);
CorrelationIdServletFilter CorrelationIdServletFilter = mock(
    CorrelationIdServletFilter.class);
CorrelationIdServletFilter.init(mock(FilterConfig.class));

CorrelationIdServletFilter.doFilter(httpServletRequest, httpServletResponse,
    filterChain);


System.out.println(httpServletResponse.getHeaderNames());

CorrelationIdServletFilter.destroy();

verify(CorrelationIdServletFilter, times(1))
    .doFilter(httpServletRequest, httpServletResponse, filterChain);

}

有什么办法可以做到吗?任何帮助将非常感激。有没有办法在没有模拟的情况下做到这一点?

【问题讨论】:

  • 请使用Java命名约定;变量名以小写字母开头。您的代码看起来像是在调用静态方法(这很混乱),因为您没有遵循这些规则。

标签: java servlets correlation servlet-filters dropwizard


【解决方案1】:

您编写的测试的一些主要问题:

  1. 永远不会模拟被测类(可能有一些例外),因为您希望实际调用以对被测类的各种方法进行单元测试。
  2. 我们应该始终为被测类的不同方法编写单独的单元测试。在这里,我可以看到您还调用了 initdestroy 方法,当您想测试 doFilter 方法时不需要这些方法。
  3. 当我们创建任何模拟对象时,我们使用期望来定义我们期望对模拟对象进行的调用,并让它们返回一些存根值(如果需要)。

现在,我尝试编写正确的测试来断言您要测试的两种情况:

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

HttpServletRequest httpServletRequest = mock(HttpServletRequest.class);
HttpServletResponse httpServletResponse = mock(HttpServletResponse.class);
FilterChain filterChain = mock(FilterChain.class);
CorrelationIdServletFilter correlationIdServletFilter = new CorrelationIdServletFilter();

expect(httpServletRequest.getHeader(CORRELATION_ID_HEADER_NAME)).andReturn(""); // Empty correlation id in the request

Capture capturedCorrelationIdRaw = newCapture();

httpServletResponse.addHeader(CORRELATION_ID_HEADER_NAME, capture(capturedCorrelationIdRaw));
expectLastCall(); // used for void methods in EasyMock framework

filterChain.doFilter(httpServletRequest, httpServletResponse);
expectLastCall();

CorrelationIdServletFilter.doFilter(httpServletRequest, httpServletResponse,
    filterChain);


assertNotEmpty(capturedCorrelationIdRaw.getValue());


verify(httpServletRequest, times(1))
    .getHeader(CORRELATION_ID_HEADER_NAME);
verify(httpServletResponse, times(1))
    .addHeader(CORRELATION_ID_HEADER_NAME, anyString);

}

此测试需要根据所使用的实际测试框架进行更新,但我已尽力让您了解测试的外观。

【讨论】:

    猜你喜欢
    • 2011-08-03
    • 2019-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多