Isolated Controller Test can't instantiate Pageable

18,400

Solution 1

Original answer:

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();

Updated (2020): It is not necessary to add the ViewResolver anymore.

Regarding the parallel answer: It does not solve the problem for the original question to have this test running without ApplicationContext and/or friends.

Solution 2

Just add @EnableSpringDataWebSupport for test. Thats it.

Solution 3

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();
Share:
18,400
Jens Schauder
Author by

Jens Schauder

Softwaredeveloper, Blogger, nitpick. Spring Data committer.

Updated on June 05, 2022

Comments

  • Jens Schauder
    Jens Schauder almost 2 years

    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.

  • Bastian Voigt
    Bastian Voigt over 6 years
    I added @EnableSpringDataWebSupport annotation to my test class, but this did not have any effect. Could you give some more details on how this is supposed to work? -1 for now
  • K.Nicholas
    K.Nicholas almost 6 years
    Should be the correct answer. If your unit test is still failing check to see if the error returned is different. Could be you've moved on to a different bug.
  • Catarina Nogueira
    Catarina Nogueira almost 6 years
    why this works? Can you give more explanation so i can understand better how to overcome situations when it happens again? :-)
  • Dalibor Filus
    Dalibor Filus almost 6 years
    Adding @EnableSpringDataWebSupport to the test class doesn't solve it for me - still the same exception: No primary or default constructor found for interface org.springframework.data.domain.Pageable. Is this dependent on some package?
  • Dalibor Filus
    Dalibor Filus almost 6 years
    Sooo.... I had to remove @DataJpaTest and move BackendApplication upper one level.
  • Yu Tian Toby
    Yu Tian Toby over 2 years
    not working for my case