简体   繁体   中英

Unit Testing doFilter for Correlation Id

I am working on an application build using dropwizard.

I made a filter to intercept and log the correlation ID of the calling service.

If the incoming request doesn't have a header "Correlation-Id" in its header, we would attach one to the response.

The following is the filter:

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() {}
}

I need to write unit tests for covering two cases:

  1. When a request is sent without correlation Id. Check a id is generated on server side.

  2. When a response is sent with correlation Id. Check it is sent back with a response.

Can anyone point me how this can be done?

I tried using mock but I am not the response has nothing in header.

@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);

}

Is there any way I can do this? Any help would be really appreciated. Is there a way to this this without mock?

Some of the major issues with the test you have written :

  1. The class under test is never mocked(there can be some exceptions) because you want to make actual calls for unit testing the various methods of the class under test.
  2. We should always write separate unit tests for different methods of the class under test. Here I can see you are also calling the init and the destroy methods which is not needed when you want to test the doFilter method.
  3. When we create any mock objects, we use expectations to define the calls we are expecting to make to the mock objects and have them return some stubbed value, if required.

Now, I have tried to write the correct test which would assert both the cases you want to test:

@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);

}

This test needs to be updated according to the actual testing framework being used, but I have tried my best to give you the idea of how the test should look like.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM