【问题标题】:With Spring 3.1, How do you test urls for your controllers?使用 Spring 3.1,如何测试控制器的 url?
【发布时间】:2012-10-08 04:56:09
【问题描述】:

在 spring (3.0) 的早期版本中,可以使用 ApplicationContext 中的 RequestMappingHandlerAdapter 和 HandlerMapping 对象通过正确的 url 测试您的控制器。但是,在 Spring 3.1 中,情况发生了变化,我用来完成这项工作的代码不再起作用。

如何在 Spring 3.1 中测试 Spring 控制器 URL?例如,我想编写如下代码:

ModelAndView modelAndView = handle("GET", "/businesses");

这样,除了控制器的动作逻辑之外,我还在测试我的映射。

特别是,我最感兴趣的是确保我可以传递会话属性并将它们正确传递给我的控制器操作的@Valid 注释。

Spring 3.1 有什么方法可以做到这一点吗?

这是我使用的代码:

protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    final HandlerMapping handlerMapping = applicationContext.getBean(RequestMappingHandlerMapping.class);

    final HandlerExecutionChain handler = handlerMapping.getHandler(request);
    assertNotNull("No handler found for request, check you request mapping", handler);

    final Object controller = handler.getHandler();

    final HandlerInterceptor[] interceptors = handlerMapping.getHandler(request).getInterceptors();
    for (HandlerInterceptor interceptor : interceptors) {
        final boolean carryOn = interceptor.preHandle(request, response, controller);
        if (!carryOn) {
            return null;
        }
    }

    return handlerAdapter.handle(request, response, controller);
}

protected ModelAndView handle(String method, String path, String queryString) throws Exception {
    request.setMethod(method);
    request.setRequestURI(path);

    if(queryString != null) {
        String[] parameters = queryString.split("&");
        for(String parameter : parameters) {
            String[] pair = parameter.split("=");
            if(pair.length == 2) {
                request.setParameter(pair[0], pair[1]);
            } else {
                request.setParameter(pair[0], "");
            }
        }
    }

    return handle(request, response);
}

protected ModelAndView handle(String method, String path, String attribute, Object object) throws Exception {
    MockHttpSession session = new MockHttpSession();
    session.setAttribute(attribute, object);
    request.setSession(session);

    return handle(method, path, null);
}

protected ModelAndView handle(String method, String path) throws Exception {
    return handle(method, path, null);
}

protected void assertContentType(ModelAndView modelAndView, String contentType) {
    assertEquals(contentType, modelAndView.getView().getContentType());
}

【问题讨论】:

    标签: java spring unit-testing spring-mvc controller


    【解决方案1】:

    让我推荐spring-test-mvc,它目前在 1.0.0M1 中,但计划与更新的 Spring MVC 版本一起打包。它应该能够很容易地处理您正在寻找的案例,您的测试最终将如下所示:

    xmlConfigSetup("classpath:/META-INF/spring/web/webmvc-config.xml")
                .configureWebAppRootDir("src/main/webapp", false).build()
                .perform(get("/businesses").param("name", "param1"))
                .andExpect(status().isOk())
                .andExpect(view().name("viewname"));
    

    您的测试看起来确实适合 3.1,所以如果您仍想继续使用您的方法,您能否准确指出什么不工作 - 听起来正常请求正在通过,但会话属性似乎没有绑定?

    【讨论】:

    • 是的,会话属性没有正确绑定。这种方法曾经在 Spring 3.0 中工作得很好,但它已经停止工作了。这可能是一个错误吗?传递给控制器​​的对象现在似乎是空实例。使用 spring-test-mvc 方法,我可以像以前一样传递会话对象吗?如果是这样,我切换没有问题。该项目只有 2 天 - 我还没有写很多代码。在我全力以赴之前,我还在想办法。
    • 怀疑它是否可能是一个错误 - Spring MVC 代码在 3.0 和 3.1 之间发生了相当大的变化,处理程序不再是控制器,它实际上是最终的 @RequestMapped 方法。您的代码对于 Spring 3.0 进一步不正确,因为 RequestMappingHandlerAdapter 仅在 3.1.0 中引入。我假设会话属性应该正确使用 mvc-test - 这是一个示例 - github.com/SpringSource/spring-test-mvc/blob/master/src/test/…
    • 这里是关于这个项目的更多信息 - rossenstoyanchev.org/blog/2012/06/28/…
    • 我的代码看起来像 3.1.0 的原因是我一直试图让它在 3.1 上工作。之前的代码取自一个 3.0 项目,所以请相信我——它曾经工作得很好。我改变它的唯一原因是它停止工作。当我进行上述更改时,它只是“有点”起作用 - 但它仍然不适用于属性(这是一个大问题)。我将只使用新的 spring mvc 测试框架。据我所知,没有理由不这样做。谢谢!
    【解决方案2】:

    这是我在 Spring 3.1 中使用的测试用例之一。希望能满足你的要求。

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration({"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml" })
    public class ControllerTest {
        @Autowired
        private RequestMappingHandlerAdapter handleAdapter;
    
        @Autowired
        private RequestMappingHandlerMapping handlerMapping;
        @Test
        public void playerControllerTest() throws Exception{
    
            MockHttpServletRequest request = new MockHttpServletRequest();
            MockHttpServletResponse response = new MockHttpServletResponse();
            request.setRequestURI("/players.show");
            request.setMethod("GET");
    
            Object handler = handlerMapping.getHandler(request).getHandler();
            ModelAndView mav = handleAdapter.handle(request, response,handler);
    
            ModelAndViewAssert.assertViewName(mav,"players");
    
        }
    
    }
    

    【讨论】:

    • 这实际上与我使用的代码非常相似。如果将对象放入会话属性中,它将不起作用。会话将无法正确绑定到操作。相反,该对象似乎是一个新创建的对象。
    【解决方案3】:

    Here 是一个非常好的演示文稿,它讨论了测试 Spring 3.1 类和控制器,以下是一个示例:

    @Test
    public void testSave() {
    
        Account account = new Account();
        BindingResult result = 
            new BeanPropertyBindingResult(account, "account");
    
        AccountManager mgr = createMock(AccountManager.class);
        mgr.saveOrUpdate(account);
        replay(mgr);
    
        AccountController contrlr = new AccountController(mgr);
    
        String view = contrlr.save(account, result);
    
        assertEquals("redirect:accounts", view);
        verify(mgr);
    }
    

    希望有帮助!

    【讨论】:

    • 我很清楚您可以像调用任何其他 pojo 一样调用控制器的方法,但这不会测试映射。因此,如果映射错误,它们将未经测试,直到您在 tomcat 中尝试。除了测试控制器的逻辑之外,我宁愿对映射进行回归测试
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-12
    • 2013-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-05
    • 1970-01-01
    相关资源
    最近更新 更多