javaspring-bootspring-testmockmvcspring-test-mvc

How to specify date format for MockMvc standalone setup


I have an endpoint like this:

@GetMapping("/path")
public ResponseDTO<Page<Program>> getProgramsByUserId(@PathVariable String userId,
                                                      Pageable pageable,
                                                      @RequestParam(required = false) LocalDate from,
                                                      @RequestParam(required = false) LocalDate to) {

    return null;
}

And spring property

spring:
  mvc:
    format:
      date: iso

for specifying date format for my request params. And I have a test for my controller:

@ExtendWith(MockitoExtension.class)
class Test {

    private MockMvc mockMvc;

    @InjectMocks
    private Controller controller;

    private final ObjectMapper objectMapper = new ObjectMapper();


    @BeforeEach
    void setUp() {
        objectMapper.registerModule(new JavaTimeModule());
        mockMvc = MockMvcBuilders
                .standaloneSetup(controller)
                .setControllerAdvice(new GlobalControllerAdvice())
                .setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
                .build();
    }

    @Test
    void test() throws Exception {
        //given
        var pageable = PageRequest.of(0, 5);
        var from = LocalDate.of(2022, 1, 1);
        var to = LocalDate.of(2022, 12, 31);

        MvcResult mvcResult = mockMvc.perform(get("/path")
                        .param("page", pageable.getPageNumber() + "")
                        .param("size", pageable.getPageSize() + "")
                        .param("from", from.toString())
                        .param("to", to.toString()))
                .andExpect(status().isOk())
                .andReturn();
    }

}

where i build my mockMvc as standaloneSetup.

Problem: when I run my test it fails to convert date from string in format 2022-01-01 into LocalDate object, because this test doesn't use Spring properties and probably cannot, since I am using standaloneSetup

Question: how to configure my mockMvc to be able to convert string date into LocalDate object?

Note: I know, that I can use @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) annotation for my request param, but I want to do it globally via spring property.


Solution

  • This can be done by adding WebConversionService to mockMvc:

    mockMvc = MockMvcBuilders
            .standaloneSetup(controller)
            .setConversionService(
                    new WebConversionService(new DateTimeFormatters().dateFormat("iso"))
                )
            .setControllerAdvice(new GlobalControllerAdvice())
            .setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
            .build();
    
    

    Time and Date Time Format can be set similarly, refers to DateTimeFormatters

    How to find this?

    1. I search for property spring.mvc.format.time in the library and see found spring-configuration-metadata.json
       {
         "name": "spring.mvc.format.date",
         "type": "java.lang.String",
         "description": "Date format to use, for example 'dd\/MM\/yyyy'.",
         "sourceType": "org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties$Format"
       },
      
    2. Then I check who is using WebMvcProperties$Format#getDate() and it leads me to WebMvcAutoConfiguration#mvcConversionService
       @Bean
       @Override
       public FormattingConversionService mvcConversionService() {
           Format format = this.mvcProperties.getFormat();
           WebConversionService conversionService = new WebConversionService(new DateTimeFormatters()
                   .dateFormat(format.getDate()).timeFormat(format.getTime()).dateTimeFormat(format.getDateTime()));
           addFormatters(conversionService);
           return conversionService;
       }