Spring MVC 使用Spring MockMVC测试Spring的@RequestBody

8wtpewkr  于 2023-06-23  发布在  Spring
关注(0)|答案(5)|浏览(172)

我正在尝试使用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测试此方法?

vof42yt1

vof42yt11#

用这个

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)。
有关HTTP请求主体结构的更多信息

lc8prwob

lc8prwob2#

下面的工作对我来说,

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);
    }
}
e3bfsja2

e3bfsja23#

问题是,您正在使用自定义Gson对象序列化bean,而应用程序正在尝试使用JacksonObjectMapper(在MappingJackson2HttpMessageConverter内)反序列化JSON。
如果打开服务器日志,应该会看到类似这样的内容

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具有相同的日期格式。

jv4diomz

jv4diomz4#

我在Spring的最新版本中也遇到过类似的问题。我尝试使用new ObjectMapper().writeValueAsString(...),但它不会在我的情况下工作。
我实际上有一个JSON格式的String,但我觉得它实际上是将每个字段的toString()方法转换为JSON。在我的例子中,date 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)
);
fdx2calv

fdx2calv5#

你也可以从文件中轻松获取json内容,当内容很大时,这很有帮助。
可以创建通用包并添加静态方法

public static String getRequestBodyFromFile(String fileLocation) throws IOException {
        File file = ResourceUtils.getFile(String.format("classpath:%s", fileLocation));
        return new String(Files.readAllBytes(file.toPath()));
    }

然后将文件添加到测试资源中并在测试时加载

mockMvc.perform(post("/yourpath")
                            .contentType(MediaType.APPLICATION_JSON)
                            .content(getRequestBodyFromFile("resourcespath/yourjsonfile.json")))
                .andExpect(status()
                        .isOk())

希望会对某人有所帮助。

相关问题