52 votes

Comment l'unité de test d'un contrôleur Spring MVC à l'aide de @PathVariable?

J'ai une simple annoté contrôleur de similaire à ceci:

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

et je veux le tester avec un appareil de test comme ceci:

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
  }
}

Le problème est que AnnotationMethodHandlerAdapter.handler() la méthode lève une 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)

46voto

scarba05 Points 1624

Je parlerais de ce que vous êtes après un test d'intégration basé sur la terminologie au Printemps manuel de référence. Comment faire quelque chose comme:

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
    }
}

Pour plus d'informations, j'ai écrit un billet de blog à propos de test d'intégration de Spring MVC annotations.

37voto

Jonathan Points 789

Dès le Printemps 3.2, il est un bon moyen de tester ce, dans un cadre élégant et facile. Vous serez en mesure de faire des choses comme ça:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("servlet-context.xml")
public class SampleTests {

  @Autowired
  private WebApplicationContext wac;

  private MockMvc mockMvc;

  @Before
  public void setup() {
    this.mockMvc = webAppContextSetup(this.wac).build();
  }

  @Test
  public void getFoo() throws Exception {
    this.mockMvc.perform(get("/foo").accept("application/json"))
        .andExpect(status().isOk())
        .andExpect(content().mimeType("application/json"))
        .andExpect(jsonPath("$.name").value("Lee"));
  }
}

Pour plus d'informations, jetez un oeil à http://blog.springsource.org/2012/11/12/spring-framework-3-2-rc1-spring-mvc-test-framework/

10voto

tbruyelle Points 5323

Un cadre prometteur pour le test de Spring MVC https://github.com/SpringSource/spring-test-mvc

3voto

skaffman Points 197885

Le message se réfère à un "flux" de la variable, ce qui n'est pas présent dans votre exemple de code, il est susceptible d'être causée par quelque chose que vous n'avez pas montré.

Aussi, votre test est un test de Printemps et de votre propre code. Est-ce vraiment ce que vous voulez faire?

Il est préférable de supposer que les travaux du Printemps (ce qu'il fait), et de tester la qualité de votre propre classe, c'est à dire appel MyController.doSomething() directement. C'est un des avantages de l'approche d'annotation - vous n'avez pas besoin d'utiliser de se moquer de demandes et de réponses, il vous suffit d'utiliser le domaine Pojo.

2voto

Emil Sit Points 11326

J'ai trouvé que vous pouvez insérer manuellement un PathVariable de la cartographie dans l'objet de requête. C'est clairement non-idéal, mais semble fonctionner. Dans votre exemple, quelque chose comme:

@Test
public void test() {
    MockHttpServletRequest request = new MockHttpServletRequest();
    request.setRequestURI("/test.html");
    HashMap<String, String> pathvars = new HashMap<String, String>();
    pathvars.put("id", "test");
    request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, pathvars);
    new AnnotationMethodHandlerAdapter().handle(request, new MockHttpServletResponse(), new MyController());
   // assert something
}

Je serais certainement être intéressé à trouver une meilleure option.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X