2013-08-20 21 views
102

devo semplice test di integrazioneCome controllare String nel corpo di risposta con mockMvc

@Test 
public void shouldReturnErrorMessageToAdminWhenCreatingUserWithUsedUserName() throws Exception { 
    mockMvc.perform(post("/api/users").header("Authorization", base64ForTestUser).contentType(MediaType.APPLICATION_JSON) 
      .content("{\"userName\":\"testUserDetails\",\"firstName\":\"xxx\",\"lastName\":\"xxx\",\"password\":\"xxx\"}")) 
      .andDo(print()) 
      .andExpect(status().isBadRequest()) 
      .andExpect(?); 
} 

In ultima riga voglio mettere a confronto stringa ricevuta nel corpo risposta alla stringa prevista

E in risposta ottengo:

MockHttpServletResponse: 
      Status = 400 
    Error message = null 
     Headers = {Content-Type=[application/json]} 
    Content type = application/json 
      Body = "Username already taken" 
    Forwarded URL = null 
    Redirected URL = null 

Provato alcuni trucchi con content(), body() ma niente ha funzionato.

+11

Proprio come consiglio, 400 codice di stato non deve essere restituito per qualcosa come '" Nome utente già preso "'. Questo dovrebbe essere più di un 409 conflitto. –

+0

Grazie - l'obiettivo di questo test è specificare tali cose. – abrasadera

risposta

50

@Sotirios Delimanolis risposta fare il lavoro ma ero alla ricerca di confronto tra le stringhe all'interno di questa affermazione mockMvc

Così qui è

.andExpect(content().string("\"Username already taken - please try with different username\"")); 

Naturalmente la mia affermazione venga meno;

java.lang.AssertionError: Response content expected: 
<"Username already taken - please try with different username"> but was:<"Something gone wrong"> 

perché:

MockHttpServletResponse: 
      Body = "Something gone wrong" 

Quindi questa è la prova che funziona!

+8

Nel caso qualcuno abbia messaggi con ID dinamici, come ho fatto io, è utile sapere che il metodo string() accetta anche un hamcrest * containsString * matcher: '.eExpect (content(). stringa (containsString (" \ "Nome utente già preso"); ' – molholm

+3

Attenzione, se stai utilizzando Spring MVC per REST (ad esempio @RestController)' content' è sempre vuoto e invece 'modello' deve essere usato per verificare le risposte –

+1

@ TimBüthe, che non è corretto.Se hai un problema di questo tipo dovresti postarlo come una domanda perché non è sicuramente il comportamento previsto, né è un comportamento Ho visto nel mio codice – Paul

176

È possibile chiamare andReturn() e utilizzare l'oggetto MvcResult restituito per ottenere il contenuto come String. Vedi sotto:

MvcResult result = mockMvc.perform(post("/api/users").header("Authorization", base64ForTestUser).contentType(MediaType.APPLICATION_JSON) 
      .content("{\"userName\":\"testUserDetails\",\"firstName\":\"xxx\",\"lastName\":\"xxx\",\"password\":\"xxx\"}")) 
      .andDo(print()) 
      .andExpect(status().isBadRequest()) 
      .andReturn(); 

String content = result.getResponse().getContentAsString(); 
// do what you will 
+10

Attenzione, se si utilizza Spring MVC per REST (ad esempio @RestController), 'content' è sempre vuoto e invece' model' deve essere usato per verificare le risposte. –

+6

@ TimBüthe Puoi chiarire? Un '@ RestController' indica che tutti i metodi del gestore sono annotati implicitamente con' @ ResponseBody'. Ciò significa che Spring userà un 'HttpMessageConverter' per serializzare il valore di ritorno del gestore e scriverlo nella risposta. Puoi ottenere molto il corpo con 'content()'. –

+5

@SotiriosDelimanolis è corretto ... Sto guardando proprio ora il JSON restituito da 'getContentAsString()' che proviene dal mio controller '@ RestController'. – Paul

31

Spring MockMvc ora ha il supporto diretto per JSON. Quindi, basta dire:

.andExpect(content().json("{'message':'ok'}")); 

e, a differenza di confronto di stringa, si dirà qualcosa come "xyz campo mancante" o "messaggio previsto 'ok' arrivato 'nok'

Questo metodo è stato introdotto nella primavera del 4.1. .

+1

potresti fornire un esempio completo? Non è necessario 'ContentRequestMatchers' per supportare questa funzione? – Zarathustra

0
String body = mockMvc.perform(bla... bla).andReturn().getResolvedException().getMessage() 

Questo dovrebbe dare il corpo della risposta. "Nome utente già presa" nel tuo caso.

+0

dove la spiegazione? È necessario o puoi darlo nel commento di questo tipo di risposta – user1140237

24

Leggendo queste risposte, vedo un sacco relativo alla versione 4.x Primavera, io sono utilizzando la versione 3.2.0 per vari motivi. Quindi cose come il supporto JSON direttamente dal content() non sono possibili.

Ho trovato che usare MockMvcResultMatchers.jsonPath è davvero facile e funziona a meraviglia. Ecco un esempio di test di un metodo post.

Il bonus con questa soluzione è che si stanno ancora facendo corrispondenze sugli attributi, non facendo affidamento sui confronti completi delle stringhe json.

(Usando org.springframework.test.web.servlet.result.MockMvcResultMatchers)

String expectedData = "some value"; 
mockMvc.perform(post("/endPoint") 
       .contentType(MediaType.APPLICATION_JSON) 
       .content(mockRequestBodyAsString.getBytes())) 
       .andExpect(status().isOk()) 
       .andExpect(MockMvcResultMatchers.jsonPath("$.data").value(expectedData)); 

Il corpo della richiesta era solo una stringa JSON, che si può facilmente caricare da un file di dati finto vero JSON, se si voleva, ma non ho includere che qui come avrebbe deviato dalla domanda.

JSON effettivo restituito avrebbe guardato come questo:

{ 
    "data":"some value" 
} 
4

di sicurezza primavera @WithMockUser e containsString matcher di hamcrest fa per una semplice ed elegante soluzione:

@Test 
@WithMockUser(roles = "USER") 
public void loginWithRoleUserThenExpectUserSpecificContent() throws Exception { 
    mockMvc.perform(get("/index")) 
      .andExpect(status().isOk()) 
      .andExpect(content().string(containsString("This content is only shown to users."))); 
} 

More examples on github

1

Tratto da della primavera tutorial

mockMvc.perform(get("/" + userName + "/bookmarks/" 
      + this.bookmarkList.get(0).getId())) 
      .andExpect(status().isOk()) 
      .andExpect(content().contentType(contentType)) 
      .andExpect(jsonPath("$.id", is(this.bookmarkList.get(0).getId().intValue()))) 
      .andExpect(jsonPath("$.uri", is("http://bookmark.com/1/" + userName))) 
      .andExpect(jsonPath("$.description", is("A description"))); 

is è disponibile presso import static org.hamcrest.Matchers.*;

jsonPath è disponibile da import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;

e jsonPath di riferimento può essere trovato here

Problemi correlati