Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit test a Spring MVC controller using @PathVariable?

I have a simple annotated controller similar to this one:

@Controller public class MyController {   @RequestMapping("/{id}.html")   public String doSomething(@PathVariable String id, Model model) {     // do something     return "view";   } } 

and I want to test it with an unit test like this:

public class MyControllerTest {   @Test   public void test() {     MockHttpServletRequest request = new MockHttpServletRequest();     request.setRequestURI("/test.html");     new AnnotationMethodHandlerAdapter()       .handle(request, new MockHttpServletResponse(), new MyController());     // assert something   } } 

The problem is that AnnotationMethodHandlerAdapter.handler() method throws an exception:

java.lang.IllegalStateException: Could not find @PathVariable [id] in @RequestMapping at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.resolvePathVariable(AnnotationMethodHandlerAdapter.java:642) at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolvePathVariable(HandlerMethodInvoker.java:514) at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:262) at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:146) 
like image 724
martiner Avatar asked Sep 09 '09 18:09

martiner


People also ask

How do you use PathVariable?

The @PathVariable annotation is used to extract the value from the URI. It is most suitable for the RESTful web service where the URL contains some value. Spring MVC allows us to use multiple @PathVariable annotations in the same method. A path variable is a critical part of creating rest resources.

Is SpringBootTest a unit test?

No. A unit test is to test a single component in isolation. Using constructor injection in your beans allows you to very simply call new SomeService(myMock) , no Spring required.


1 Answers

I'd call what you're after an integration test based on the terminology in the Spring reference manual. How about doing something like:

import static org.springframework.test.web.ModelAndViewAssert.*;  @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({/* include live config here     e.g. "file:web/WEB-INF/application-context.xml",     "file:web/WEB-INF/dispatcher-servlet.xml" */}) public class MyControllerIntegrationTest {      @Inject     private ApplicationContext applicationContext;      private MockHttpServletRequest request;     private MockHttpServletResponse response;     private HandlerAdapter handlerAdapter;     private MyController controller;      @Before     public void setUp() {        request = new MockHttpServletRequest();        response = new MockHttpServletResponse();        handlerAdapter = applicationContext.getBean(HandlerAdapter.class);        // I could get the controller from the context here        controller = new MyController();     }      @Test     public void testDoSomething() throws Exception {        request.setRequestURI("/test.html");        final ModelAndView mav = handlerAdapter.handle(request, response,             controller);        assertViewName(mav, "view");        // assert something     } } 

For more information I've written a blog entry about integration testing Spring MVC annotations.

like image 151
scarba05 Avatar answered Oct 28 '22 12:10

scarba05