web-dev-qa-db-fra.com

Test de @RequestBody de Spring à l'aide de Spring MockMVC

J'essaie de tester une méthode qui publie un objet dans la base de données à l'aide de la structure MockMVC de Spring. J'ai construit le test comme suit:

@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();
}

La méthode que je teste utilise @RequestBody de Spring pour recevoir l'ObjectBean, mais le test renvoie toujours une erreur 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;
}

Le json créé par gson dans le test:

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

La classe 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
}

Ma question est donc la suivante: comment tester cette méthode avec Spring MockMVC?

43
Matt

Utilisez celui-ci

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

Comme décrit dans les commentaires, cela fonctionne car l'objet est converti en json et transmis en tant que corps de la demande. En outre, le contentType est défini en tant que Json (APPLICATION_JSON_UTF8).

Plus d'informations sur la structure du corps de la requête HTTP

58
Priyanka Gupta

ce qui suit fonctionne pour moi,

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

Le problème est que vous sérialisez votre bean avec un objet personnalisé Gson alors que l’application tente de désérialiser votre JSON avec un Jackson ObjectMapper (dans MappingJackson2HttpMessageConverter).

Si vous ouvrez les journaux de votre serveur, vous devriez voir quelque chose comme:

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"])

parmi d'autres traces de pile.

Une solution consiste à définir votre format de date Gson sur l'un des formats ci-dessus (dans la pile).

L'alternative est d'enregistrer votre propre MappingJackson2HttpMessageConverter en configurant votre propre ObjectMapper pour qu'il ait le même format de date que votre Gson.

5