Come posso testare una classe che richiede una chiamata al servizio web?

20

Sto provando a testare una classe che chiama alcuni servizi web Hadoop. Il codice è più o meno della forma:

method() {
    ...use Jersey client to create WebResource...
    ...make request...
    ...do something with response...
}

es. esiste un metodo di creazione directory, un metodo di creazione cartella ecc.

Dato che il codice ha a che fare con un servizio web esterno di cui non ho il controllo, come posso testarlo? Potrei provare a prendere in giro il client / le risposte del servizio web, ma questo infrange le linee guida che ho visto molto di recente: "Non prendere in giro oggetti che non possiedi". Potrei creare un'implementazione fittizia del servizio web - sarebbe ancora un "test unitario" o sarebbe un test di integrazione? Non è possibile eseguire il test unitario a questo livello basso? Come farebbe un praticante del TDD per questo?

    
posta Chris Cooper 11.10.2013 - 16:26
fonte

5 risposte

38

Secondo me dovresti prendere in giro le chiamate al webservice se si tratta di un test unitario, al contrario di un test di integrazione.

Il test dell'unità non deve verificare se il webservice esterno funziona o se l'integrazione con esso è corretta. Senza diventare troppo dogmatici riguardo a TDD, si noti che un effetto collaterale di trasformare il test dell'unità in un test di integrazione è che è probabile che funzioni più lentamente e si desidera test di unità veloci .

Inoltre, se il servizio web è temporaneamente inattivo o non funziona correttamente, ciò potrebbe causare il fallimento del test dell'unità? Non sembra giusto. Il tuo test unitario dovrebbe fallire per una sola ragione: se c'è un errore nel codice in quella "unità".

L'unica porzione di codice pertinente qui è ...do something with response... . Mock il resto.

    
risposta data 11.10.2013 - 16:53
fonte
5

Non sono d'accordo con "non prendere in giro oggetti che non possiedi" quando fai il test unitario.

Lo scopo di esistenza dei mazzi è il fatto che ci saranno moduli, librerie, classi che non possediamo.

Il mio suggerimento per il tuo scenario è la chiamata al servizio web.

Configura il mock in modo da restituire i dati al tuo modulo.
Assicurati di coprire tutti gli scenari, ad esempio quando i dati restituiti sono nulli, quando i dati restituiti sono validi ecc.

E per il codice che possiedi, la tua responsabilità come sviluppatore è quella di garantire che il codice che stai producendo si comporti come previsto in tutti gli scenari.

    
risposta data 11.11.2013 - 05:11
fonte
1

Vorrei usare qualcosa come EasyMock per questo test. I framework di simulazione sono un modo ideale per rimuovere le dipendenze esterne in una classe e offrono un controllo totale sul risultato delle dipendenze esterne durante i test. Per estendere un po 'il tuo esempio:

class WebClass {

private WebServiceInterface webserviceInterface;

    void method(){
        R result = webServiceInterface.performWebServiceCall();
        ... do something with result
    }

    public void setWebServiceInterface(WebServiceInterface webServiceInterface){
        this.webServiceInterface = webServiceInterface;
    }
}


interface WebServiceInterface {

   R performWebServiceCall();

}


class WebClassTest {

private WebServiceInterface mock;    
private R sampleResult = new R();

    @Before
    public void before(){
        mock = EasyMock.createMock(WebServiceInterface.class);
    }


    @Test
    public void test() {
        WebClass classUnderTest = new WebClass();
        EasyMock.expect(mock.performWebServiceCall()).andReturn(sampleResult);
        classUnderTest.setWebServiceInterface(mock);
        classUnderTest.method();
        EasyMock.verify(mock);
    }
}

La prima cosa che devi fare è estrarre la logica della tua classe in cui usi Jersey per ottenere una WebResource e chiamare il servizio web in una classe separata. La creazione di un'interfaccia per questa classe ti consentirà di creare un mock a cui è possibile dettare il comportamento.

Una volta creata questa interfaccia, puoi creare una simulazione usando EasyMock, che restituirà un oggetto specificato che si adatta al tuo caso di test. L'esempio sopra mostra una semplificazione del modo in cui strutturare un test mocked di base e come funzionerà la tua interfaccia.

Per ulteriori informazioni sui framework di simulazione, consultare questa domanda . Inoltre, questo esempio presuppone l'utilizzo di Java, ma i framework di simulazione sono disponibili in tutte le lingue e sebbene vengano implementati in modo diverso, funzioneranno generalmente allo stesso modo

    
risposta data 11.10.2013 - 18:38
fonte
1

I mock sono accettabili in questo caso, ma non ne hai bisogno. Invece del test unitario method() , invece unità test solo la parte che gestisce la risposta.

Estrai una funzione che richiede ResponseData (di qualsiasi tipo sia appropriato) e poi esegue l'azione.

Invece di fare il mocking, ora basta costruire un oggetto ResponseData e passarlo.

Puoi lasciare la chiamata del servizio ai test di integrazione completa, che copriranno method() in totale

    
risposta data 08.05.2015 - 19:35
fonte
0

Cosa ho fatto e funziona:

  1. Avere tutto il codice chiama webservices tramite proxy.
  2. Il proxy chiama una classe che sa in modo statico se stiamo usando proxy o meno e reindirizza di conseguenza. I mazzi sono solo HashMaps che per ogni richiesta restituisce una determinata risposta.
  3. Esegui i test più volte in questo ordine:

3.1 Innanzitutto vengono testati tutti i webservice. Da ogni macchina, anche le macchine dello sviluppatore. Questi sono i veri servizi web, ma sono in corso di sviluppo. Ciò significa che i servizi web non possono mai essere inattivo o rispondere a valori errati, perché altrimenti ogni sviluppatore si lamenta di non poterlo compilare.

3.2 Quindi vengono eseguiti tutti i test unitari interni all'applicazione. Ciò significa che tutti i webservice sono presi in giro e testati eseguendo gli stessi test di 3.1 (anbde dovrebbero anche passarli, altrimenti i mock out sono sbagliati), e invocati dall'applicazione reale come se fossero realmente utilizzati. Se i mock sono sbagliati, puoi eseguire il test in 3.1 e registrare quei valori (richiesta, risposta) in una HashMap.

3.3 Quindi vengono eseguiti gli stessi test di 3.2, ma questa volta contro i servizi Web reali in esecuzione nell'ambiente di sviluppo.

Dopo che tutti questi sono stati completati, per il vero ambiente di produzione è sufficiente fornire l'indirizzo reale per ogni webservice. Speriamo che questo non richieda troppi cambiamenti nella configurazione.

    
risposta data 08.05.2015 - 19:15
fonte

Leggi altre domande sui tag