How to mock HttpServletRequest with Headers?
As a starting point and demonstration for the principal you can start with the following snippet.
// define the headers you want to be returned
Map<String, String> headers = new HashMap<>();
headers.put(null, "HTTP/1.1 200 OK");
headers.put("Content-Type", "text/html");
// create an Enumeration over the header keys
Enumeration<String> headerNames = Collections.enumeration(headers.keySet());
// mock HttpServletRequest
HttpServletRequest request = mock(HttpServletRequest.class);
// mock the returned value of request.getHeaderNames()
when(request.getHeaderNames()).thenReturn(headerNames);
System.out.println("demonstrate output of request.getHeaderNames()");
while (headerNames.hasMoreElements()) {
System.out.println("header name: " + headerNames.nextElement());
}
// mock the returned value of request.getHeader(String name)
doAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
return headers.get((String) args[0]);
}
}).when(request).getHeader("Content-Type");
System.out.println("demonstrate output of request.getHeader(String name)");
String headerName = "Content-Type";
System.out.printf("header name: [%s] value: [%s]%n",
headerName, request.getHeader(headerName));
}
Output
demonstrate output of request.getHeaderNames()
header name: null
header name: Content-Type
demonstrate output of request.getHeader(String name)
header name: [Content-Type] value: [text/html]
For HttpServletRequest
, I would recommend using a fully functional mock type instead of directly mocking it with Mockito mocks. The spring-test
library has MockHttpServletRequest
for this purpose:
@BeforeClass
public static void init(){
// ...
MockHttpServletRequest mockRequest = new MockHttpServletRequest();
mockRequest.addHeader("Content-Type", "text/html");
mockRequest.addHeader("if-none-match", "*");
mockRequest.addHeader("customHeader", "customValue");
this.request = mockRequest;
}
Rationale
HttpServletRequest
is a complex interface with over 20 methods, with well-defined interplay between them. Using a fully functional mock type for HttpServletRequest
from a library simplifies the mocking, removing the need to carefully mock out the methods you're using.
One advantage of this approach is that it is more resilient in the face of future refactorings that get the same information using other methods on the class. In the case of retrieving the "if-none-match" header in HttpServletRequest
, I see three different methods that could legitimately be used to retrieve the header: getHeader(String name)
, getHeaders(String name)
, and getHeaderNames()
. Furthermore, the argument for both getHeader
and getHeaders
are case-insensitive (the same results are returned for "if-none-match", "If-None-Match", etc.), so any possible argument casing would be correct. It's very possible to support this with a direct mock, though it involves extra boilerplate code that complicates the test and makes it less obvious.
The MockHttpServletRequest
class from the spring-test
library mocks this interface, and allows setting the header and other values via a straightforward API. While the library is designed for testing Spring applications, the MockHttpServletRequest
class is independent of any Spring-specific functionality, and should be completely usable on its own even if the application doesn't use Spring.