使用Spring MockMVC测试Spring的@RequestBody

时间:2013-12-10 20:20:18

标签: spring-mvc integration-testing

我正在尝试使用Spring的MockMVC框架测试将对象发布到数据库的方法。我构建了如下测试:

@Test
public void testInsertObject() throws Exception { 

    String url = BASE_URL + "/object";

    ObjectBean anObject = new ObjectBean();
    anObject.setObjectId("33");
    anObject.setUserId("4268321");
    //... more

    Gson gson = new Gson();
    String json = gson.toJson(anObject);

    MvcResult result = this.mockMvc.perform(
            post(url)
            .contentType(MediaType.APPLICATION_JSON)
            .content(json))
            .andExpect(status().isOk())
            .andReturn();
}

我正在测试的方法使用Spring的@RequestBody来接收ObjectBean,但测试总是返回400错误。

@ResponseBody
@RequestMapping(    consumes="application/json",
                    produces="application/json",
                    method=RequestMethod.POST,
                    value="/object")
public ObjectResponse insertObject(@RequestBody ObjectBean bean){

    this.photonetService.insertObject(bean);

    ObjectResponse response = new ObjectResponse();
    response.setObject(bean);

    return response;
}

gson在测试中创建的json:

{
   "objectId":"33",
   "userId":"4268321",
   //... many more
}

ObjectBean类

public class ObjectBean {

private String objectId;
private String userId;
//... many more

public String getObjectId() {
    return objectId;
}

public void setObjectId(String objectId) {
    this.objectId = objectId;
}

public String getUserId() {
    return userId;
}

public void setUserId(String userId) {
    this.userId = userId;
}
//... many more
}

所以我的问题是:如何使用Spring MockMVC测试此方法?

4 个答案:

答案 0 :(得分:45)

使用此

public static final MediaType APPLICATION_JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));

@Test
public void testInsertObject() throws Exception { 
    String url = BASE_URL + "/object";
    ObjectBean anObject = new ObjectBean();
    anObject.setObjectId("33");
    anObject.setUserId("4268321");
    //... more
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
    ObjectWriter ow = mapper.writer().withDefaultPrettyPrinter();
    String requestJson=ow.writeValueAsString(anObject );

    mockMvc.perform(post(url).contentType(APPLICATION_JSON_UTF8)
        .content(requestJson))
        .andExpect(status().isOk());
}

如评论中所述,这是有效的,因为对象被转换为json并作为请求体传递。此外,contentType定义为Json(APPLICATION_JSON_UTF8)。

More info on the HTTP request body structure

答案 1 :(得分:6)

以下对我有用的

  mockMvc.perform(
            MockMvcRequestBuilders.post("/api/test/url")
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(asJsonString(createItemForm)))
            .andExpect(status().isCreated());

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

答案 2 :(得分:4)

问题是,当应用程序尝试使用Jackson Gson(在ObjectMapper内)反序列化您的JSON时,您正在使用自定义MappingJackson2HttpMessageConverter对象序列化您的bean。

如果打开服务器日志,您应该会看到类似

的内容
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of java.util.Date from String value '2013-34-10-10:34:31': not a valid representation (error: Failed to parse Date value '2013-34-10-10:34:31': Can not parse date "2013-34-10-10:34:31": not compatible with any of standard forms ("yyyy-MM-dd'T'HH:mm:ss.SSSZ", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "EEE, dd MMM yyyy HH:mm:ss zzz", "yyyy-MM-dd"))
 at [Source: java.io.StringReader@baea1ed; line: 1, column: 20] (through reference chain: com.spring.Bean["publicationDate"])

其他堆栈跟踪。

一种解决方案是将Gson日期格式设置为上述之一(在堆栈跟踪中)。

另一种方法是通过将自己的MappingJackson2HttpMessageConverter配置为与ObjectMapper具有相同的日期格式来注册您自己的Gson

答案 3 :(得分:0)

我在使用较新版本的 Spring 时遇到了类似的问题。我尝试使用 new ObjectMapper().writeValueAsString(...),但在我的情况下不起作用。

我实际上有一个 JSON 格式的 String,但我觉得它实际上是将每个字段的 toString() 方法转换为 JSON。就我而言,日期 LocalDate 字段最终会是:

<块引用>

"date":{"year":2021,"month":"JANUARY","monthValue":1,"dayOfMonth":1,"chronology":{"id":"ISO","calendarType" :"iso8601"},"dayOfWeek":"FRIDAY","leapYear":false,"dayOfYear":1,"era":"CE"}

这不是在请求中发送的最佳日期格式...

最后,就我而言,最简单的解决方案是使用 Spring ObjectMapper。它的行为更好,因为它使用 Jackson 构建具有复杂类型的 JSON。

@Autowired
private ObjectMapper objectMapper;

我只是在测试中使用了它:

mockMvc.perform(post("/api/")
                .content(objectMapper.writeValueAsString(...))
                .contentType(MediaType.APPLICATION_JSON)
);