Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock HttpServletRequest with Headers?

I am using Mockito with JUnit to test an application. I need to add headers to an HttpServletRequest while mocking. This is the first time I am using mock concept to test the application. How can we set headers to the request object while using this mock concept?

Application code

@Produces({ MediaType.APPLICATION_JSON })
@Path("/devices")
public class DvrRestService {
    private static final Logger logger = LoggerFactory.getLogger(DvrRestService.class);

    private DvrMiddleService dvrMiddleService;

    @Inject
    public DvrRestService(DvrMiddleService dvrMiddleService) {
        this.dvrMiddleService = dvrMiddleService;
    }

    @GET 
    @Path("/{deviceId}/metadata")
    public Response getDeviceMetadata(@Context HttpServletRequest request, @PathParam("deviceId") String deviceId,
        @RequiredSession final Session session) {

        try {
            public static String[] REQUEST_HEADERS = { "if-none-match" };
            List<String> requiredHeaders = Lists.newArrayList(REQUEST_HEADERS);
            Map<String, String> headers = new HashMap<String, String>();

            Enumeration<String> headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()) { // here gettting NullPointerException

                String headerName = headerNames.nextElement();
                if (requiredHeaders.contains(headerName.toLowerCase())) {
                    String value = request.getHeader(headerName);
                    if (value != null) {
                        headers.put(headerName, value);
                        System.out.println("headerName: " + headerName + ", Value: " + value);
                    }
                }
            }
            DvrResponse response = dvrMiddleService.getDeviceMetadata(deviceId.toUpperCase(), getHeaders(request));
            return processResponse(response.statusCode, response.getResponse(), DeviceMetadataResponse.class,
                response.getHeaders());
        } catch (Exception e) {
            return processErrorResponse(e, new DeviceMetadataResponse(), logger);
        }

    }
}

Test

public class DvrRestServiceTest {

    static DvrMiddleService dms;
    static HttpServletRequest request;
    static Session session;
    static DvrRestService drs;
    public static final String DeviceId = "000004D42070";
    @BeforeClass
    public static void init(){
        dms = mock(DvrMiddleService.class);
        request = mock(HttpServletRequest.class);
        session = mock(Session.class);
        drs = new DvrRestService(dms);
    }
    @Test
    public void getDeviceMetadataTest(){
        Response rs = drs.getDeviceMetadata(request, DeviceId, session);
        assertEquals(Response.Status.OK, rs.getStatus());
    }
}
like image 427
Sat Avatar asked May 19 '16 05:05

Sat


People also ask

How do you add a header request in Junit?

MockHttpServletRequest request = new MockHttpServletRequest(); request. addHeader("x-real-ip","127.0. 0.1");

What is MockHttpServletRequest?

public class MockHttpServletRequest extends Object implements HttpServletRequest. Mock implementation of the HttpServletRequest interface. The default, preferred Locale for the server mocked by this request is Locale. ENGLISH . This value can be changed via addPreferredLocale(java.


2 Answers

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]
like image 80
SubOptimal Avatar answered Oct 28 '22 13:10

SubOptimal


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.

like image 43
M. Justin Avatar answered Oct 28 '22 12:10

M. Justin