2012-06-12 13 views
25

Ho scritto codice che chiama l'API client di Jersey che a sua volta chiama un servizio Web fuori dal mio controllo. Non voglio che il mio test di unità chiami il servizio web attuale.Come si esegue il test del codice dell'unità che chiama l'API del client Jersey?

Qual è l'approccio migliore per scrivere un test di unità per il codice che chiama l'API del client Jersey? Devo utilizzare l'API del server Jersey per scrivere un servizio web JAX-RS e quindi utilizzare il Jersey Test Framework per il test dell'unità? O dovrei prendere in giro le chiamate di servizio web Jersey? Ho accesso a JMock. O dovrei provare un altro approccio?

Durante la mia ricerca, ho trovato this discussion che descrive varie opzioni, ma ho trovato una soluzione completa. Sono disponibili esempi di codice che mostrano un approccio JUnit suggerito? Non ho trovato nulla nella documentazione di Jersey.

Ecco il codice sorgente relativo:

public String getResult(URI uri) throws Exception { 
    // error handling code removed for clarity 
    ClientConfig clientConfig = new DefaultClientConfig(); 
    Client client = Client.create(clientConfig); 
    WebResource service = client.resource(uri); 
    String result = service.accept(accept).get(String.class); 
    return result; 
} 

Ecco alcuni esempi di codice di prova che vorrei passare. Vorrei testare (1) passare un URI valido e ottenere una stringa valida indietro e (2) passare un URI non valido (per qualsiasi motivo - non raggiungibile o non autorizzato) e ottenere indietro un'eccezione.

@Test 
public void testGetResult_ValidUri() throws Exception { 
    String xml = retriever.getResult(VALID_URI); 
    Assert.assertFalse(StringUtils.isBlank(xml)); 
} 

@Test(expected = IllegalArgumentException.class) 
public void testGetResult_InvalidUri() throws Exception { 
    retriever.getResult(INVALID_URI); 
} 

Tutto sopra è la semplice descrizione di ciò che fa il mio codice. In realtà, sopra c'è un livello che accetta due URI, prima prova a chiamare il primo URI, e se quell'URI fallisce, prova a chiamare il secondo URI. Mi piacerebbe avere dei test unitari che coprano (1) il primo URI ha esito positivo, (2) il primo URI fallisce e il secondo URI ha esito positivo e (3) entrambi gli URI falliscono. Questo codice è sufficientemente complesso che voglio testare questi diversi scenari usando JUnit, ma per fare questo ho bisogno sia di eseguire servizi web stand-in che di prendere in giro le chiamate API client di Jersey.

+0

cosa esattamente vuoi testare in questo metodo? Quali sono i criteri, che test è passato? – dbf

+0

Bene, se si desidera eseguire un test unitario, è necessario disporre dei servizi funzionali appropriati. – iDroid

+0

@dbf Ho aggiornato la domanda con cui voglio testare (1) passare un URI valido e ottenere una stringa valida indietro e (2) passare un URI non valido (per qualsiasi ragione - non raggiungibile o non autorizzato) e ottenere un'eccezione indietro. – BennyMcBenBen

risposta

12

Prova a utilizzare Mockito o Easymock per le chiamate di servizio. Hai bisogno di prendere in giro solo questi metodi che sono effettivamente utilizzati - non c'è bisogno di prendere in giro ogni metodo. È possibile creare un oggetto fittizio per la classe WebResource, quindi simulare accettare la chiamata al metodo.

In @ BeforeClass/@ Prima di test JUnit qualcosa di simile metodo write (Mockito esempio)

WebResource res = mock(WebResource.class); 
when(res.accept(something)).thenReturn(thatWhatYouWant); 

Poi nei test si può usare res oggetto come se fosse oggetto reale e finta chiamata al metodo su di esso. Invece di restituire un valore, puoi anche generare eccezioni. Mockito è abbastanza bello.

+1

Questa è la risposta corretta. Fare un intero servizio web sta spendendo gli sforzi per testare il codice Jersey quando so già che funziona. Voglio testare il mio codice. Alla fine ho dovuto refactoring le chiamate al codice di Jersey in un'altra classe, aggiungendo un setter e prendendo in giro la nuova classe. Questo ha funzionato perfettamente e mi ha permesso di testare i diversi scenari che volevo testare. Il mio team sta usando JMock quindi ho finito per usarlo, ma qualsiasi framework di derisione funzionerà. – BennyMcBenBen

+0

Sono un po 'confuso dal momento che il sito Web di Mockito recita "Non fare il finto tipo che non possiedi!" Dove tracciamo una linea su cosa possiamo prendere in giro rispetto al contrario. C'è un modo migliore? –

0

Basta implementare un servizio simile al lavoro e nella configurazione dell'unità di test avviare il servizio utilizzando HttpServerFactory.

11

In genere ciò che si sta veramente cercando è "il modo in cui utilizzo il DSL Jersey Client produce una richiesta all'URL corretto con il carico utile e i parametri URL corretti". Testare questo con Mockito è davvero prolisso e il codice di impostazione di solito finiscono per guardare qualcosa di simile:

when(authentication.queryParam(eq("sa"), anyBoolean())).thenReturn(testAuthentication); 
    when(testAuthentication.resolveTemplate("channel", "smf")).thenReturn(testAuthentication); 
    when(testAuthentication.request(
      MediaType.APPLICATION_JSON_TYPE)).thenReturn(mockRequestBuilder); 
    when(mockRequestBuilder.post(any(Entity.class))).thenReturn(mockResponse); 
    when(mockResponse.readEntity(ResponseWrapper.class)).thenReturn(successfulAuthResponse()); 

E questo è fondamentalmente solo per una singola richiesta REST. È eccessivamente prolisso e, invece di testare il risultato sperato, stai semplicemente replicando i passaggi che ritieni corretti utilizzando il DSL Jersey Client.

Invece di quanto sopra, vorrei mirare a prendere in giro un servizio semplice.Per questo ho usato WireMock che avvia un server Jetty e dove posso stub cose come "aspettarsi una richiesta a questo URL, rispondere con questo messaggio e verificare che il carico utile sia questo".

So che questo è un test di integrazione ed è un po 'più lento del semplice utilizzo di Mockito ma apprezzo il test del risultato reale e apprezzo molto la leggibilità dei test in questo caso.

installazione per un test di WireMock client Jersey base simile a questa:

@Test 
public void exactUrlOnly() { 
    stubFor(get(urlEqualTo("/some/thing")) 
      .willReturn(aResponse() 
       .withHeader("Content-Type", "text/plain") 
       .withBody("Hello world!"))); 

    assertThat(testClient.get("/some/thing").statusCode(), is(200)); 
    assertThat(testClient.get("/some/thing/else").statusCode(), is(404)); 
} 
+0

+1 per WireMock: ottimo strumento. Nel mio caso, Mockito non ha potuto prendere in giro WebResource.Builder (finale), risolto con WireMock – denismo

Problemi correlati