Vale davvero la pena testare l'unità di un client API?


38

Questo è qualcosa che mi preoccupa da un po 'di tempo. Vale davvero la pena testare l'unità di un client API?

Supponiamo che tu stia creando una piccola classe per sottrarre le chiamate a un'API REST di petshop. Il negozio di animali domestici è un'API molto semplice e ha una serie di metodi di base:

  • listProducts()
  • getProductDetails(ProductID)
  • addProduct(...)
  • removeProduct(ProductID)

Nel testare questo, dovremmo creare un servizio simulato o deridere le risposte. Ma questo sembra eccessivo; Capisco che vogliamo assicurarci che i nostri metodi non smettano di funzionare attraverso errori di battitura / di sintassi, ma dal momento che stiamo scrivendo funzioni che chiamano metodi remoti e quindi stiamo creando risposte false da quei metodi remoti, sembra uno spreco di sforzi e che stiamo testando qualcosa che non può davvero fallire. Peggio ancora, se il metodo remoto cambia, i nostri test unitari passeranno mentre l'uso della produzione fallisce.

Sono abbastanza sicuro che mi manchi qualcosa, o ho la parte sbagliata del bastone, o non vedo il legno per gli alberi. Qualcuno può mettermi sulla strada giusta?


1
Se questa non fosse un'API così semplice con metodi di base, ti sentiresti diverso? Anche una tettoia deve resistere alla neve.
JeffO

Risposte:


31

Il compito di un client API remoto è di emettere determinate chiamate, né più né meno. Pertanto, il suo test dovrebbe verificare che emetta tali chiamate, né più né meno.

Certo, se il provider API modifica la semantica delle loro risposte, il sistema non funzionerà correttamente nella produzione. Ma non è colpa della tua classe cliente; è qualcosa che può essere catturato solo nei test di integrazione. Facendo affidamento su codice non sotto il tuo controllo hai rinunciato alla possibilità di verificare la correttezza tramite test interni: era un compromesso e questo è il prezzo.

Detto questo, testare una classe che consiste solo di deleghe in un'altra classe può essere a bassa priorità, perché c'è relativamente poco rischio di errori complessi. Ma questo vale per qualsiasi classe che consiste solo di una linea uniforme, non ha nulla a che fare con la chiamata al codice di un altro fornitore.


Mmm, non sono sicuro di essere d'accordo. Puoi provare che foo()viene chiamato prima bar(), ma ciò non significa che chiamare foo()prima bar()sia la cosa giusta da fare; un test unitario del genere passerebbe anche se il codice è errato. E se è tutto ciò che il client sta facendo, impostare le beffe che controllano se foo()viene chiamato prima bar()è relativamente problematico per qualcosa che può essere verificato con una rapida occhiata al codice del client.
Doval,

1
Puoi provare che un add()metodo aggiunge correttamente due numeri, ma ciò non significa che aggiungere sia la cosa giusta da fare a questo punto dell'algoritmo: il add()test unitario avrebbe successo anche se il tuo programma è sbagliato. Se è la cosa sbagliata, allora levenshteinDistance()è colpa del tuo metodo, non del add()metodo. Questo è esattamente lo stesso. Il punto di avere il codice separato in metodi è che ogni metodo deve solo preoccuparsi di ottenere una cosa corretta.
Kilian Foth,

3
Ora vedo dove non siamo d'accordo! Se fai affidamento su un negozio di animali esterno, per me questo significa che il tuo sistema termina al limite HTTP, quindi le chiamate REST emesse sono output e soggette a test. Se consideri il negozio di animali parte di questo modulo, allora sì, lo schema delle chiamate emesse è un dettaglio di implementazione e un test unitario non ha alcuna attività commerciale che prescriva qualcosa al riguardo.
Kilian Foth,

2
"Pertanto, il suo test dovrebbe verificare che emetta tali chiamate" Penso che sia la prospettiva che non riuscivo a vedere. Grazie!
Phillip B Oldham,

1
Quindi ad esempio il mio test unitario potrebbe verificare che, dati alcuni parametri, il corpo della richiesta che si tratta di eseguire sia quello corretto?
Maria Ines Parnisari,

9

Risposta breve:

Tutti i metodi devono essere testati in unità.

Risposta lunga:

Sì. Ne vale la pena.

Queste sono alcune cose che i test unitari su quei metodi di chiamata API dovrebbero testare:

  • Che stai passando parametri ben formati o corretti alle chiamate API.
  • Che stai rispondendo di conseguenza a determinati tipi di dati restituiti dalle API (derisi o meno), ad esempio forse quando l'API restituisce una stringa vuota, il tuo metodo dovrebbe restituire un valore predefinito (solo un esempio)
  • Che i metodi del chiamante si comportino correttamente quando le chiamate API generano un errore

Queste sono le cose che il metodo chiamato fa e che possono isolare il mio deridere il servizio API e che provandole bene, ti assicurano che gli errori non sono originati da un errore nel codice client che chiama l'API.


Dici "deriso o no" ... quindi va bene testare con la vera API? Posso chiamarlo test di integrazione anche se sembra un test unitario? O c'è un'altra cosa da chiamare questo? Mi piacerebbe provare che il mio wrapper API fa quello che dice, in qualche modo ...
Dan Rosenstark,

1
@DanRosenstark Immagino che nel caso in cui il servizio API non venga deriso, è un test di integrazione.
Tulains Córdova,

Non sapresti tra 5 secondi se stai recuperando correttamente i dati quando effettui una chiamata effettiva all'API? Dal momento che i mock API non sono chiamate reali, l'unico modo in cui fallirebbero è se cambiassero l'API ... in quel caso i test di simulazione passerebbero ma le chiamate reali fallirebbero. Sembra inutile
MattE

5

Questi non sarebbero test unitari perché stai testando l'input e l'output del tuo sistema, più come i test di integrazione limitati.

Sii molto cauto quando dici "sembra uno spreco di sforzi e che stiamo testando qualcosa che non può davvero fallire" - può fallire, fallirà, probabilmente fallirà in modi che non puoi anticipare, il i guasti peggioreranno se non si dispone di test in atto.

L'errore che stai facendo qui ha a che fare con l'invenzione delle ruote: effettuare chiamate a servizi remoti e API è uno scenario molto comune, quindi ci sono alcuni strumenti abbastanza buoni per aiutarti a provarlo. L'ultima volta che stavo lavorando su un'applicazione connessa a servizi remoti ho usato SoapUIche potrebbe guardare un servizio e fare chiamate simulate a quel servizio o comportarsi come una copia locale del server su cui è possibile effettuare chiamate di prova e tenere traccia delle richieste e delle risposte. Ci sono voluti pochi minuti per l'installazione e allo stesso modo è stato molto rapido aggiornare se l'interfaccia remota è cambiata. Non l'ho usato in uno scenario REST, ma anche se non funziona bene per quello (o forse qualcuno leggerà questa risposta in futuro quando esistono strumenti migliori) dovresti essere in grado di trovare uno strumento che può deridere un servizio per te e quando arriva il momento di distribuire il tuo codice, sarai felice di averlo fatto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.