集成测试 将整个对象POST到Spring MVC控制器

有没有办法在集成测试弹簧mvc Web应用程序时在模拟请求上传递整个表单对象?我所能找到的就是将每个字段作为参数单独传递,如下所示:

mockMvc.perform(post("/somehwere/new").param("items[0].value","value"));

这对于小形式来说很好。但是,如果我发布的对象变大了怎么办?此外,如果我可以发布整个对象,它使测试代码看起来更好。

具体来说,我想通过复选框测试多个项目的选择,然后发布它们。当然,我可以只测试发布单个项目,但我想知道。

我们使用的是 spring 3.2.2,包括 spring-test-mvc。

窗体的我的模型如下所示:

NewObject {
    List<Item> selection;
}

我尝试过这样的调用:

mockMvc.perform(post("/somehwere/new").requestAttr("newObject", newObject) 

到控制器,如下所示:

@Controller
@RequestMapping(value = "/somewhere/new")
public class SomewhereController {

    @RequestMapping(method = RequestMethod.POST)
    public String post(
            @ModelAttribute("newObject") NewObject newObject) {
        // ...
    }

但是对象将是空的(是的,我之前在测试中填充了它)

我发现的唯一工作解决方案是使用这样的@SessionAttribute:Spring MVC应用程序的集成测试:表单

但是我不喜欢必须记住在我需要的每个控制器结束时调用complete的想法。毕竟,所有表单数据不必在会话内部,我只需要一个请求。

因此,我现在唯一能想到的就是编写一些 Util 类,该类使用 MockHttpServletRequestBuilder 将所有对象字段作为 .param 使用反射或为每个测试用例单独附加。

我不知道,感觉不直观。

关于如何让我的喜欢更容易的任何想法/想法?(除了直接调用控制器)

谢谢!


答案 1

我有同样的问题,事实证明,通过使用JSON编组器,解决方案相当简单。
让控制器通过更改为 来更改签名。喜欢这个:@ModelAttribute("newObject")@RequestBody

@Controller
@RequestMapping(value = "/somewhere/new")
public class SomewhereController {

    @RequestMapping(method = RequestMethod.POST)
    public String post(@RequestBody NewObject newObject) {
        // ...
    }
}

然后在测试中,您可以简单地说:

NewObject newObjectInstance = new NewObject();
// setting fields for the NewObject  

mockMvc.perform(MockMvcRequestBuilders.post(uri)
  .content(asJsonString(newObjectInstance))
  .contentType(MediaType.APPLICATION_JSON)
  .accept(MediaType.APPLICATION_JSON));

其中方法只是:asJsonString

public static String asJsonString(final Object obj) {
    try {
        final ObjectMapper mapper = new ObjectMapper();
        final String jsonContent = mapper.writeValueAsString(obj);
        return jsonContent;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}  

答案 2

集成测试的主要目的之一是验证模型对象是否相应地填充了表单数据。MockMvc

为此,您必须传递表单数据,因为它们是从实际表单传递的(使用)。如果您使用一些从数据到数据的自动转换,您的测试将不会涵盖特定类别的可能问题(与实际形式不兼容的修改)。.param()NewObjectNewObject