使用MockMVC测试Spring MVC路由器

问题描述:

我正在尝试使用Spring测试来测试我的Spring MVC webapp。它使用 springmvc-router 进行路由,这似乎打破了测试,当我使用 @RequestMapping 代替我的 routes.conf 文件时工作正常。

I'm trying to test my Spring MVC webapp with Spring test. It uses springmvc-router for routing and that appears to break the tests, which work fine when I use @RequestMapping instead of my routes.conf file.

我有一个名为 valid.jsp .jsp 文件,它显示正常我从Jetty运行开发站点。控制器是:

I have a .jsp file called valid.jsp, and it displays fine when I run the development site from Jetty. The controller is:

@Controller
@EnableWebMvc
public class AuthController {
  public String valid() {
    return "valid";
  }
}

我的 routes.conf 文件映射 GET /有效authController.valid

现在,我的测试人员看起来像

Now, my tester looks like

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/test-context.xml",
    "/spring/spring-security.xml",
    "file:src/main/webapp/WEB-INF/mvc-config.xml"})
@WebAppConfiguration
@Import(RouteConfig.class)
public class AuthControllerTest {
  private MockMvc mockMvc;

  @Autowired
  private WebApplicationContext webApplicationContext;

  @Autowired
  private AuthenticationManager authenticationManager;

  @Before
  public void init() {
    MockitoAnnotations.initMocks(this);
    mockMvc =
        MockMvcBuilders.webAppContextSetup(webApplicationContext).dispatchOptions(true).build();
  }

  @Test
  public void testValid() throws Exception {
    mockMvc.perform(get("/validation-success"))
        .andDo(print())
        .andExpect(status().isOk());
  }

mockMvc.perform()$运行c $ c>,抛出NullPointerException:

When the mockMvc.perform() is run, a NullPointerException is thrown:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:943)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:822)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:807)
    at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:64)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
    at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:170)
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:137)
    at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:141)
    at com.mypackage.AuthControllerTest.testValid(AuthControllerTest.java:45)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:232)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:175)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:77)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.NullPointerException
    at org.resthub.web.springmvc.router.HTTPRequestAdapter.parseRequest(HTTPRequestAdapter.java:196)
    at org.resthub.web.springmvc.router.RouterHandlerMapping.getHandlerInternal(RouterHandlerMapping.java:166)
    at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:300)
    at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1101)
    at org.springframework.test.web.servlet.TestDispatcherServlet.getHandler(TestDispatcherServlet.java:104)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:916)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:876)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:931)
    ... 41 more

所以问题是:是否可以使用Spring的测试框架springmvc-router?

So the question is: is it possible to use Spring's test framework with springmvc-router?

在做了一些挖掘之后,我发现了 HTTPRequestAdapter.parseRequest( )方法与Mock的方式有问题MVC发送请求。具体来说,MockMVC发送的请求在请求中不包含名称为 host 的标头。

After doing some digging, I've discovered that the HTTPRequestAdapter.parseRequest() method has an issue with the way that MockMVC sends requests. Specifically, the request sent by MockMVC doesn't include a header in the request with the name host.

HTTPRequestAdapter 需要该标头并且不考虑它可以为空的事实,因此它生成 NullPointerException

HTTPRequestAdapter requires that header and does not account for the fact that it can be null, so it generates the NullPointerException.

我修复了此代码的问题:

I fixed the issue with this code:

mockMvc.perform(get("/validation-success")
       .header("host", "localhost:80"))
       .andExpect(status().isOk());

主机标头不会为空并且你的测试应该通过。

The host header won't be null and your tests should pass.