I have a Spring MVC Controller which uses Pagination Support of Spring-Data:
@Controller
public class ModelController {
private static final int DEFAULT_PAGE_SIZE = 50;
@RequestMapping(value = "/models", method = RequestMethod.GET)
public Page<Model> showModels(@PageableDefault(size = DEFAULT_PAGE_SIZE) Pageable pageable, @RequestParam(
required = false) String modelKey) {
//..
return models;
}
}
And I'd like to test the RequestMapping using the nice Spring MVC Test Support. In order to keep these tests fast and isolated from all the other stuff going on, I do not want to create the complete ApplicationContext:
public class ModelControllerWebTest {
private MockMvc mockMvc;
@Before
public void setup() {
ModelController controller = new ModelController();
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
@Test
public void reactsOnGetRequest() throws Exception {
mockMvc.perform(get("/models")).andExpect(status().isOk());
}
}
This approach works fine with other Controllers, that do not expect a Pageable, but with this one I get one of these nice long Spring stacktraces. It complains about not being able to instantiate Pageable:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.data.domain.Pageable]: Specified class is an interface
at
.... lots more lines
Question: How do I change my test so the magic No-Request-Parameter-To-Pageable conversion happens properly?
Note: In the actual application everything is working fine.
The problem with pageable can be solved by providing a custom argument handler. If this is set you will run in a ViewResolver Exception (loop). To avoid this you have to set a ViewResolver (an anonymous JSON ViewResolver class for example).
mockMvc = MockMvcBuilders.standaloneSetup(controller)
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.setViewResolvers(new ViewResolver() {
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return new MappingJackson2JsonView();
}
})
.build();
Just add @EnableSpringDataWebSupport for test. Thats it.
For spring boot simply adding the ArgumentResolvers solved for me:
From code which triggered the error:
this.mockMvc = MockMvcBuilders.standaloneSetup(weightGoalResource).build();
To this, which works:
this.mockMvc = MockMvcBuilders.standaloneSetup(weightGoalResource)
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.build();
Just stumpled upon this.
I wanted to provide an answer to this.
If you don´t want to test for Pageable
functionality just leave it out.
Tested on Spring Boot 2.0.6:
Controller´s code:
@RequestMapping(value = "/searchbydistance/{distance}/{address}/page")
public String searchByDistance(@PathVariable int distance,
@PathVariable @NonNull String address,
Model model, Pageable pageable,
Locale locale,
RedirectAttributes redirectAttributes) {
}
Test code:
@Test
@WithMockUser(username = "user", authorities = {"AdminRole"})
public void testSearchByDistance() {
try {
UriComponents uri = UriComponentsBuilder.fromUriString("/joboffers/searchbydistance/{distance}/{address}/page").buildAndExpand(10, "Deggendorf");
this.mockMvc.perform(get(uri.toUri())).andExpect(status().isOk());
} catch (Exception e) {
log.error(e.getMessage());
}
}
Hope this helps ...
Kind regards
Thomas
来源:https://stackoverflow.com/questions/22174665/isolated-controller-test-cant-instantiate-pageable