DivDiff
DivDiff

Reputation: 983

How to pass date objects as request parameters through Spring MockMvc

I have a unit test that uses Spring's MockMvc testing framework to hit a REST endpoint. The rest endpoint requires that two string path variables be sent, along with two java.util.Date objects which are passed as @RequestParameters. When I run the test, it fails because the Date objects are either not present, or can't be serialized from a string JSON representation to a Date object. For the record, execution fails before hitting the end point listed in the .perform(), so this problem is not coming from the code being tested. It's coming from the test.

Here's my test:

    @Test
    public void testGetHitsForCell() {
    String categoryName = "categoryName";

    try {

        String startDateJson = gson.toJson(new Date());
        String endDateJson = gson.toJson(new Date());
        ResultActions ra = mvc.perform(MockMvcRequestBuilders.get("/rest/tickets/" + ticketName + "/" + categoryName).requestAttr("startDate", new Date())
                .requestAttr("endDate", new Date()).with(user(user)));
        MvcResult aResult = ra.andReturn();
        MockHttpServletResponse response = aResult.getResponse();

        assertTrue(response.getContentType().equals("application/json;charset=UTF-8"));
        assertTrue(gson.fromJson(response.getContentAsString(), PaginatedResults.class) instanceof PaginatedResults);
    } catch (Exception e) {
        e.printStackTrace();
        fail(e.getMessage());
    }

The endpoint looks like this:

/rest/ticket/{ticketName}/{categoryName}?startDate=2015-07-21T14%3A26%3A51.972-0400&endDate=2015-08-04T14%3A26%3A51.972-0400

This is the exception that the MockMvc throws:

org.springframework.web.bind.MissingServletRequestParameterException: Required Date parameter 'startDate' is not present

My test application context looks like this:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">


    <import resource="classpath:propertiesPlaceholder.xml" />
    <import resource="classpath:cache.xml" />
    <import resource="classpath:mongo-context.xml" />
    <import resource="classpath:securityContext.xml" />
    <import resource="classpath:service-commons.xml" />

    <import resource="classpath:mockUserProviderContext.xml" />

    <!-- Enables the Spring MVC @Controller programming model -->
    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <!-- Use the Jackson mapper defined above to serialize dates appropriately -->
            <bean
                class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper" ref="jacksonObjectMapper" />
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

    <mvc:default-servlet-handler/>
    <!-- Jackson Mapper -->
    <bean name="jacksonObjectMapper"
        class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
        <property name="featuresToDisable">
            <array>
                <util:constant
                    static-field="com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS" />
                <util:constant
                    static-field="com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS" />
            </array>
        </property>
    </bean>


    <!-- SimpleDateFormat for Jackson to use for formatting Date objects -->
    <bean id="standardDateFormat" class="java.text.SimpleDateFormat">
        <constructor-arg index="0" value="yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" />
    </bean>

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving 
        up static resources in the ${webappRoot}/resources directory -->
    <mvc:resources mapping="/resources/**" location="/resources/" />

    <context:component-scan base-package="ticketApp" />
    <context:component-scan base-package="mongodb.dao.TicketDao" />
    <context:component-scan base-package="service.commons.*" />

</beans>

What can I do to correctly pass these Date objects to the above rest endpoint?

Upvotes: 2

Views: 11434

Answers (3)

razvang
razvang

Reputation: 1285

It seems that MockMVC is stupid. This doesn't work

 this.mockMvc.perform(get()
                .queryParam("startDate","2011-01-01")
                .queryParam("endDate", "2000-11-31")

You have to hardCode the Date DIRECTLY in URL, like so:

MockHttpServletRequestBuilder mockHttpServletRequestBuilder = get(CONFIRMATION_API_GET+"?startDate=2019-09-12&endDate=2019-10-13");

Upvotes: 0

Guilherme Gambeti
Guilherme Gambeti

Reputation: 49

I know it's too late to answer, but just for future someone's search.

In order to solve this problem you can use get(URL).param instead:

mvc.perform(MockMvcRequestBuilders.get("/rest/tickets/" + ticketName + "/" + categoryName).param("startDate", new Date())
            .param("endDate", new Date()).with(user(user)));

Upvotes: 0

DivDiff
DivDiff

Reputation: 983

It turns out that a couple of things were wrong here:

I didn't need to use the .requestAttr() calls for the date objects. I simply added string representations of the dates to the call as query parameters like so:

private String end = "2015-12-31T23:59:59.999Z";
private String start = "2012-01-01T00:00:00.000Z";

ResultActions ra = mvc.perform(MockMvcRequestBuilders.get("/rest/hits/" + modelId + "/0" + "?startDate=" + start + "&endDate=" + end).with(user(user)));

Also, passing in Date objects caused an issue because their format of the string representation was wrong. Rookie mistake.

Upvotes: 1

Related Questions