【问题标题】:How do I test form submission with Spring MVC test?如何使用 Spring MVC 测试测试表单提交?
【发布时间】:2017-04-10 18:50:07
【问题描述】:

我使用 Spring 创建控制器的大部分经验都是针对使用 JSON 格式请求的 REST 控制器。我一直在寻找有关如何对表单提交进行测试的文档,到目前为止,这就是我理解它应该使用 MockMvc 的方式:

MvcResult result = mockMvc.perform(post("/submit")
                .param('title', 'test title')
                .param('description', 'test description'))
                .andReturn()

但是,我不确定如何将表单参数映射到模型对象。我已经看到@ModelAttribute 注释在我的搜索中弹出,但我不知道它应该如何用于映射。此外,官方文档中的this quick start guide 没有详细说明th:objectth:field 之类的内容如何转换为HTML,然后转换为URL 编码形式。

我的控制器代码类似于以下内容:

@PostMapping('/submit')
def submit(@ModelAttribute WriteUp writeUp) {
    //do something with writeUp object
    'result'
}

【问题讨论】:

    标签: spring spring-mvc groovy thymeleaf spring-test-mvc


    【解决方案1】:

    我已经看到 @ModelAttribute 注释在我的搜索中弹出,但我 无法弄清楚它应该如何用于映射。

    当您用@ModelAttribute 标记writeUp 对象时,Spring 容器会从HttpServletRequest 对象填充参数(如titledescription 等)并将对象注入控制器方法,当请求从客户端(可以是浏览器或MockMvc 单元测试客户端或其他任何东西)到达服务器时。

    此外,还有一些其他基本要点供您快速理解:

    (1) Controller 方法映射到一个 URI 和 RequestMethod(如 POST/GET/DELETE/PUT 等),如下所示:

        @RequestMapping(value="/submit", method=RequestMethod.POST)
        public String submit(@ModelAttribute WriteUp writeUp) {
    
           //Call the service and Save the details
    
            model.addAttribute("Writeup details added successfully");
    
            return "writeUpResult"; //Returns to the View (JSP)
         }
    

    (2) @ModelAttribute 将被映射到一个对象(如您的 writeUp),用于 http POST/PUT 请求,其中 html 格式的数据是 http 正文的一部分。

    (3) @RequestParam@PathParam 将用于参数是 URL 的一部分(即,不是 http 正文的一部分)的 http GET 请求。

    您可以查看here 以了解 DispatcherServlet 请求处理和 Spring MVC 基本 Web 流程。

    【讨论】:

    • 我想我现在主要关心的是 HTML 表单应该如何使 ModelAttribute 映射正常工作。在我的示例代码中,我有标题和描述参数。
    • 简单的例子可以参考这里:mkyong.com/spring-mvc/spring-mvc-form-handling-example
    • 重要的问题是:毕竟,我该如何测试控制器? MockMvcRequestBuilder 的哪一部分可以模拟创建绑定到提交处理程序的模型属性?
    【解决方案2】:

    我通过反复试验发现我的具体问题可能是 Groovy 特有的。事实证明,测试代码和控制器代码没有问题。重申一下,对于测试表单提交,使用param 方法到MockMvcRequestBuildersperform 方法。要注意的另一件事是,如果未指定内容类型,这似乎不起作用。这是一个适用于我的示例测试代码:

    MvcResult result = webApp.perform(post("/submit")
            .contentType(APPLICATION_FORM_URLENCODED) //from MediaType
            .param('title', 'test title')
            .param('description', 'test description'))
            .andReturn()
    

    如您所见,它与我最初发布的内容没有太大区别。控制器代码几乎相同,@ModelAttribute 工作正常。

    我的设置问题在于因为我使用的是 Groovy,所以我认为 getter 和 setter 是在我的 WriteUp 类中自动生成的。以下是 WriteUp 类最初的样子:

    class WriteUp {
        private String title
        private String description
    }
    

    我已经有一段时间没有在 Groovy 中编写代码了,上一次我这样做时,可以假定像上面这样的类隐含地具有 getter 和 setter。然而,事实证明并非如此。 为了解决我的具体问题,我将字段中的访问修饰符更新为 default(包级别)

    class WriteUp {
        String title
        String description
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-14
      • 2018-02-09
      • 2018-10-26
      • 2020-03-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多