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:
-
Escludo la classe
Client
e provo solo a chiamare i metodi appropriati. In questo modo, sto facendo lo stesso di sopra ma trattando ilClient
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. IlWrapper
potrebbe benissimo essere implementato utilizzando un client completamente diverso. -
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 veroClient
. -
Ho appena verificato che siano state fatte le richieste HTTP appropriate. Ciò significa che
Wrapper
chiamerà attraverso un oggettoClient
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?