Unit test su client e wrapper API

14

Sto girando in tondo cercando di capire il modo migliore per testare una libreria client API che sto sviluppando. La libreria ha una classe Client che ha fondamentalmente un mapping 1: 1 con l'API e una classe Wrapper aggiuntiva che fornisce un'interfaccia più user-friendly sulla parte superiore di Client .

Wrapper --> Client --> External API

Ho scritto per la prima volta una serie di test sia su Client che su Wrapper , testando in effetti solo che inoltrano alle funzioni appropriate di qualsiasi operazione ( Wrapper opera su Client e Client funziona su una connessione HTTP). Tuttavia, ho iniziato a sentirmi a disagio, perché mi sembra di provare l'implementazione di queste classi, piuttosto che l'interfaccia. In teoria, potrei cambiare le classi per avere un'altra implementazione perfettamente valida, ma i miei test fallirebbero perché le funzioni che mi aspettavo fossero chiamate non venivano chiamate. Mi sembra un test fragile.

Dopo questo, ho pensato all'interfaccia delle classi. I test dovrebbero verificare che le classi svolgano effettivamente il lavoro che intendono svolgere, piuttosto che come lo fanno. Quindi, come posso fare questo? La prima cosa che viene in mente è lo stub delle richieste API esterne. Tuttavia, sono nervoso per semplificare eccessivamente il servizio esterno. Molti degli esempi di API stubbed che ho visto forniscono solo risposte predefinite, il che sembra un modo davvero semplice per verificare solo che il codice funzioni correttamente rispetto alla tua API falsa. L'alternativa è prendere in giro il servizio, che è semplicemente irrealizzabile, e dovrebbe essere tenuto aggiornato ogni volta che cambia il servizio reale - che sembra eccessivo e spreco di tempo.

Infine, ho letto questo da un'altra risposta sui programmatori SE :

The job of a remote API client is to issue certain calls - no more, no less. Therefore, its test should verify that it issues those calls - no more, no less.

E ora sono più o meno convinto - quando collaudo Client , tutto quello che devo testare è che rende le richieste corrette all'API (Naturalmente, c'è sempre la possibilità che l'API cambierà ma i miei test continuare a passare - ma è qui che i test di integrazione potrebbero tornare utili). Poiché Client è solo un mapping 1: 1 con l'API, la mia preoccupazione prima di passare da un'implementazione valida a un'altra non si applica in realtà: esiste solo un'implementazione valida per ogni metodo di Client .

Tuttavia, sono ancora bloccato con la classe Wrapper . Vedo le seguenti opzioni:

  1. Escludo la classe Client e provo solo a chiamare i metodi appropriati. In questo modo, sto facendo lo stesso di sopra ma trattando il Client come standard per l'API. Questo mi riporta indietro da dove ho iniziato. Ancora una volta, questo mi dà la sensazione spiacevole di testare l'implementazione, non l'interfaccia. Il Wrapper potrebbe benissimo essere implementato utilizzando un client completamente diverso.

  2. Creo un mock Client . Ora devo decidere fino a che punto fare finta di prenderlo in giro - creare una simulazione completa del servizio richiederebbe un grande sforzo (più lavoro di quanto non sia stato fatto nella biblioteca stessa). L'API stessa è semplice, ma il servizio è piuttosto complesso (è essenzialmente un archivio dati con operazioni su quei dati). E ancora, dovrò mantenere il mio simulato in sincronia con il vero Client .

  3. Ho appena verificato che siano state fatte le richieste HTTP appropriate. Ciò significa che Wrapper chiamerà attraverso un oggetto Client reale per rendere quelle richieste HTTP, quindi non lo sto testando da solo. Questo lo rende un test unitario terribile.

Quindi non sono particolarmente soddisfatto di nessuna di queste soluzioni. Cosa faresti? C'è un modo giusto per fare questo?

    
posta Joseph Mansfield 23.12.2015 - 01:50
fonte

1 risposta

10

TLDR : nonostante la difficoltà, dovresti interrompere il servizio e utilizzarlo per i test dell'unità client.

Non sono sicuro che "il lavoro di un client API remoto è quello di emettere determinate chiamate, né più né meno ...", a meno che l'API non sia costituita da endpoint che restituiscono sempre uno stato fisso, e né consumare o produrre alcun dato. Questa non sarebbe l'API più utile ...

Dovresti anche controllare che il client non solo mandi le richieste corrette, ma che gestisca correttamente il contenuto della risposta, errori, reindirizzamenti, ecc. e verifica tutti questi casi.

Come noterai, dovresti avere test di integrazione che coprono l'intero stack da wrapper - > client - > servizio - > DB e oltre, ma per rispondere alla tua domanda principale, a meno che tu non abbia un ambiente in cui i test di integrazione possano essere eseguiti come parte di ogni build di CI senza un sacco di grattacapi (database di test condivisi, ecc.), Devi investire il tempo necessario per creare un stub dell'API.

Lo stub ti consente di creare un'implementazione funzionante del servizio, ma senza dover implementare alcun livello sotto il servizio stesso.

Potresti prendere in considerazione l'utilizzo di una soluzione basata su DI per eseguire questa operazione, con un'implementazione del modello di repository sotto le risorse REST:

  • Sostituisci tutti i codici funzionali nei gestori REST con le chiamate a un IWhateverRepository.
  • Crea un ProductionWhateverRepository con il codice che è stato estratto dalle risorse REST e un TestWhateverRespository che restituisce le risposte predefinite da utilizzare durante il test dell'unità.
  • Utilizzare il contenitore DI per iniettare ProductionWhateverRepository o TestWhateverRepository DLL / class, ecc. a seconda della configurazione.

Ad ogni modo, a meno che la soppressione e / o il refactoring del servizio siano fuori questione, sia politicamente che praticamente, probabilmente intraprenderei qualcosa di simile a quanto sopra. Se non fosse possibile, farei in modo di avere una copertura di integrazione davvero buona ed eseguirli tutte le volte che è possibile dare la configurazione di test disponibile.

HTH

    
risposta data 23.12.2015 - 06:40
fonte

Leggi altre domande sui tag