Talvolta capita che sia molto complicato verificare automaticamente (i.e. con delle asserzioni) la correttezza dell’output di un SUT (System Under Test). Specialmente se ci si attiene alla buona pratica di effettuare una singola asserzione per ciascun test. Esempi tipici di output difficili da verificare comprendono oggetti complessi, json, xml, testo o dati binari (tra cui immagini, video, ecc.).

La soluzione in molti casi può essere la tecnica dello snapshot testing. Sostanzialmente, si tratta di usare un output approvato manualmente dall’utente come riferimento con cui confrontare l’output del SUT durante il test. Tipicamente l’output approvato è salvato su un file (nel caso di oggetti, questi vengono serializzati).

A differenza delle tecniche tradizionali, nel caso dello snapshot testing il workflow è il seguente:

  1. Si implementa normalmente il test, ma al posto dell’asserzione si invoca un metodo opportuno che confronta l’output del SUT con quello sull’eventuale file approvato. Il test fallisce se gli output sono diversi o non esiste il file approvato;
  2. Si esegue il test una prima volta. Il test fallirà, ma genererà un file provvisorio con l’output del SUT;
  3. Il tester ispeziona manualmente il file e, se corretto, lo approva;
  4. Alle successive esecuzioni del test, se l’output rimane uguale il test avrà successo, altrimenti fallirà generando un file che il tester potrà decidere se scartare o sostituire a quello approvato.

I file approvati solitamente vengono aggiunti al progetto e al sistema di source control, in modo da essere disponibili anche ad altri tester.

Di solito, per approvare un file è sufficiente modificarne il nome o l’estensione. Molti framework si integrano comunque con i principali ambienti di sviluppo per permettere di confrontare e approvare gli output attraverso un’interfaccia grafica.

Un esempio di framework: Verify

Verify è un framework di snapshot testing per C#. Si integra con i principali framework di unit testing e vari IDE e tool di confronto tra file. Inoltre, sono disponibili vari “plugin” per testare i più svariati tipi di output, tra cui PDF, immagini, HTML, vari output relativi ad Entity framework (e.g. le query generate, le modifiche pendenti, ecc.) e molti altri.

L’integrazione di Verify nei test varia seconda del framework di unit testing utilizzato (a volte bisogna unare una specifica annotazione sulla classe di test, altre volte bisogna estendere una certa classe base, spesso bisogna anche modificare la signature del metodo di test per ritornare un Task). In ogni caso, alla fine si tratta di invocare un metodo (che solitamente si chiama proprio Verify) passando in input l’output del SUT.

Sono disponibili varie opzioni di configurazione. Le più interessanti sono quelle che riguardano la trasformazione dell’output prima di essere salvato su file. Nel caso di oggetti, ad esempio, si può decidere se salvare le date specifiche (altrimenti vengono sostituite con dei placeholder, tipo DateTime_1, e date uguali vengono sostituite con lo stesso placeholder), se sostituire i valori delle enum con i loro nomi, se salvare i GUID, ecc..

Il risultato del test viene mostrato nel test explorer insieme a quelli dei test tradizionali. In caso di conflitto tra output corrente e verificato, viene aperto un “diff tool” che mostra gli output affiancati e permette di scegliere quello da approvare.