Test unitari e derisione

Sep 14 2020

Sembra che ci siano molte domande sul "quando prendere in giro". Ma finora non ho ricevuto risposta alla mia domanda. Può essere, non conosco una specifica richiesta di ricerca che mi indichi la risposta.

Immagina di avere una classe (MyClass). Immagina che questa classe abbia metodi che possono restituire sia std :: string che un oggetto di classe wrapper (MyStringWrapper definito in un'altra libreria). MyStringWrapper non è esattamente un aggregatore (possiamo considerare di usare struct qui, ma preferiamo una classe per questo particolare esempio), poiché il suo setter ha un if e diverse operazioni di copia. Ora, c'è una terza classe (UserClass) che usa MyClass e MyStringWrapper.

In qualità di buon sviluppatore SW, vorrei testare la mia UserClass (poiché molti si riferiscono a "annusare un codice"). Per i test di unità utilizzerei gtests e gmock per creare un mock di MyClass (chiamiamolo MyClassMock). Tuttavia, ricordo che da qualche parte è stato detto "devi prendere in giro tutto, che è definito in un'altra libreria / libreria di terze parti". Sia std :: string che MyStringWrapper sono definiti in librerie di terze parti.

Adesso la domanda. Quindi, in questo caso dovrei creare mock per std :: string e MyStringWrapper?

Puoi immaginare l'utilizzo dell'oggetto std :: string / MyStringWrapper restituito come

if(myreturnedstdstring.empty())
  return 1;

if(mywrapperobject.failed())
  return 100;

Mi è stato chiesto nei commenti qui C'è un punto per i test unitari che stub e deridono tutto ciò che è pubblico?

crea un altro argomento.

Risposte

4 verisimilidude Sep 14 2020 at 16:05

Qualsiasi cosa in std :: fa parte del linguaggio e non dovrebbe essere deriso. Il tuo wrapper di stringa, se non parte dell '"unità" sotto test, può essere deriso, ma IMHO e sperimentare un wrapper del genere è generalmente così leggero che il mock riprodurrebbe essenzialmente il codice. In tal caso non lo deriderei. Tuttavia, se il wrapper potrebbe cambiare in futuro, dovresti prenderlo in giro se vuoi uno unit test stabile. D'altra parte avere un test fallito quando viene apportata una modifica incompatibile al wrapper sarebbe positivo, ma più difficile da rintracciare poiché l'errore sarà in qualche altra unità.

6 BartvanIngenSchenau Sep 15 2020 at 10:38

Ricordo che da qualche parte è stato detto "devi prendere in giro tutto, che è definito in un'altra libreria / libreria di terze parti".

Potrebbe essere stato il consiglio un tempo, ma non è il consiglio che viene comunemente dato oggi.

Il consiglio attuale è di usare il mock con parsimonia per aiutare a raggiungere questi obiettivi del test unitario:

  • I test possono essere eseguiti velocemente, in parallelo o in qualsiasi ordine e in qualsiasi momento. Ciò implica che i componenti che interagiscono con l'archiviazione persistente (database, file system), connessioni lente (di rete) o condizioni ambientali che non è possibile controllare facilmente (ad esempio il tempo) sono candidati per essere derisi.
  • Tutti i percorsi attraverso il codice sotto test possono essere esercitati. Se una certa risposta (errore) da una dipendenza non può essere facilmente attivata con il codice reale, allora potrebbe essere un motivo per deridere quella dipendenza.

Tipi di dati semplici, come le stringhe, il tuo MyStringWrapper o persino i contenitori non si adattano a questi punti, quindi non c'è motivo di deriderli.