Tipi di test automatici

I nomi assegnati a diversi tipi di test tendono ad avere temi comuni nei vari codebase, ma non hanno definizioni particolarmente rigorose. Questo corso fornisce alcune linee guida sul significato di ogni tipo di test, ma altre risorse potrebbero fornire definizioni diverse.

Nelle pagine precedenti sono stati disponibili esempi sia di test delle unità sia di test dei componenti (nel nostro esempio, con riferimenti a un componente di React). Possiamo posizionarli entrambi in basso nella nostra piramide di test (o in un'altra forma), perché hanno una bassa complessità e sono veloci da eseguire, ma potrebbero non avere la stessa utilità di un test di integrazione più complesso.

Alcuni esempi di forme di strategia di test: una piramide, un diamante taglio, un cono gelato, un esagono e un trofeo.
La strategia di test può assumere qualsiasi forma.

Tipi comuni di test

Test delle unità

I test delle unità sono i più piccoli. Questi vengono usati per testare piccole parti di codice, o puramente stateless, in modo quasi matematico: se fornisco al tuo codice gli input X, Y e Z, l'output dovrebbe essere A, B e C.

Il codice con test delle unità non avrà normalmente dipendenze esterne, come il recupero da una rete o l'uso implicito di qualsiasi altra funzione o libreria. È un nodo ad albero del codice che puoi "tagliare" e testare da solo.

Sebbene i test delle unità siano tendenzialmente rapidi da scrivere ed eseguire, è sempre possibile che il test di piccole unità di codice non fornisca informazioni utili. Spesso, la mancanza di interazione di un'unità di codice con un altro codice significa che conviene eseguire test a un livello superiore per ridurre i rischi.

Test dei componenti

Per gli sviluppatori web, il nome "componente" è sovraccarico, spesso indicando un componente visibile all'utente, come un componente React o un componente web. La sua definizione più generale è un blocco di lavoro verificabile, ad esempio una classe con dipendenze esterne. Per essere testato in modo efficace, le dipendenze di questo componente devono essere simulate o ignorate.

Poiché le moderne pratiche di sviluppo web si basano sul concetto di un componente, i test dei componenti sono un modo pratico di eseguire test: ad esempio, puoi decidere che ogni componente abbia bisogno di un test. I test dei componenti sono inoltre semplici da seguire nei contesti in cui un singolo sviluppatore o un piccolo team rivendica chiaramente la proprietà di un componente. Tuttavia, può essere difficile simulare dipendenze complesse.

Test di integrazione

Queste tendono a testare insieme un piccolo raggruppamento di componenti, moduli, sottosistemi o altre parti significative del codice per garantire che funzionino correttamente. Questa è una definizione molto vaga. Per gli sviluppatori web, immagina che il codice che stai testando non sia la build di produzione reale del tuo sito (o neanche la chiudi), ma che collega comunque vari componenti correlati del sistema.

Potrebbero essere incluse anche dipendenze "reali", ad esempio un database esterno in modalità di test, anziché una simulazione pura. Ad esempio, anziché dire che query() restituirà sempre le stesse due voci, il test di integrazione può confermare che un database di test contiene qualcosa al suo interno. I dati in sé sono meno importanti, ma ora stai testando se un database può essere connesso ed eseguire query efficaci.

È possibile scrivere test di integrazione relativamente semplici con implicazioni di vasta gamma che possono essere verificate utilizzando le asserzioni, poiché una singola azione collegata a vari componenti può causare una serie di effetti misurabili. Per questo motivo, i test di integrazione possono dimostrare in modo efficace che il tuo sistema complesso verrà eseguito come previsto. Sono difficili da scrivere e mantenere e possono introdurre complessità inutili. Ad esempio, la scrittura di un FakeUserService per un test di integrazione aggiunge il requisito che sia esso e RealUserService debbano implementare un UserService.

Test del fumo

Si tratta di test che devono essere completati molto rapidamente per determinare se il codebase è in uno stato sensato. In pratica, questo significa principalmente eseguire semplici test sul codice con effetti su larga scala.

Ad esempio, in un'app web di grandi dimensioni a cui è stato eseguito l'accesso, ciò potrebbe garantire il funzionamento del sistema di accesso e autenticazione, perché senza questa l'app è inutilizzabile e altri test non sono pertinenti.

I test fumo sono una buona candidata per l'esecuzione nello script test del file package.json, in un codebase di grandi dimensioni. I test manuali possono essere utilizzati anche come test del fumo.

Test di regressione

Il test di regressione è un tipo di test del fumo che garantisce che le funzionalità esistenti continuino a funzionare o che non vengano reintrodotti i bug precedenti dopo una nuova release o lo sviluppo di altre funzionalità.

Questo è legato al concetto di sviluppo guidato dai test (TDD). Scenari di test scritti per attivare esplicitamente un bug e successivamente utilizzati per garantire che il bug venga corretto, vengono conteggiati come scenari di test di regressione, perché la loro esistenza dovrebbe impedire la restituzione dello stesso bug.

Il test di regressione può, tuttavia, essere un problema senza un'ottima soluzione. È un termine spesso citato dalle esigenze aziendali: man mano che le caratteristiche vengono sviluppate, è importante che quelle vecchie non cedano. Un codebase ben collaudato dovrebbe essere in grado di gestirlo, ma i codebase reali non sempre sono all'altezza di questo ideale. Approfondiremo questo argomento nelle sezioni future.

Test visivi

I test visivi comprendono l'acquisizione di screenshot o video dello stato di un sito web al fine di verificare uno stato di buona nota (ad esempio uno screenshot precedente) rispetto all'esecuzione del test corrente. Per sua natura, richiede l'esecuzione di un browser reale in modo da poter visualizzare HTML, CSS e altre parti del sito web.

Anziché testare visivamente i test end-to-end che eseguono l'intero codebase, potrebbe essere utile creare "collegamenti" HTML che visualizzano solo alcuni componenti, soprattutto in diverse dimensioni dello schermo per attivare UI adattabili. Questa operazione è più complessa rispetto al semplice utilizzo di JSDOM o di framework simili.

L'esito negativo dei test visivi può essere un buon segnale di altri tipi di rottura. Tuttavia, le interfacce utente complesse possono non superare i test visivi per motivi non correlati alle funzionalità che stai provando a testare, ad esempio altre nuove funzionalità che modificano l'aspetto dell'interfaccia utente o persino una nuova versione del sistema operativo che esegue il rendering delle emoji in modo diverso rispetto alle versioni precedenti.

Test end-to-end

I test end-to-end si trovano spesso in cima alla piramide di test. Descrivono un'interazione dell'intera esperienza con la tua app web o il tuo sito web, magari incentrata su una funzionalità specifica, e in genere viene eseguita all'interno di un browser controllato da un agente come WebdriverIO, Selenium o Puppeteer, che può eseguire il tuo codebase più o meno come per il deployment in produzione (sebbene venga spesso pubblicato su localhost).

A seconda del sito, potrebbe essere necessario accedere come utente di prova, eseguire azioni importanti e verificare che il sito o il sistema sia nello stato corretto. Tratteremo altri esempi di questo tipo di test in altre sezioni, poiché possono essere molto potenti, ma a volte difficili da gestire.

Alcune tattiche per semplificarli possono includere la riduzione dell'ambito o la simulazione di componenti specifici, se pertinente. Ad esempio, se gli utenti devono accedere al tuo sito, ma l'accesso non è la funzionalità che stai testando, potresti impostare un flag per gli ambienti di test che consenta al controller di test di agire come utente senza accedere o creare i cookie associati.

Sebbene i test end-to-end possano essere contemporaneamente molto potenti per eseguire test su enormi sezioni del codebase, questi test su larga scala rischiano di essere irregolari o inaffidabili a causa della loro dipendenza da sistemi esterni. Spesso possono anche lasciare molti dati di test nel database se, ad esempio, ogni test crea o modifica una voce. L'accumulo di dati in eccesso come questo può rendere difficile determinare come un test ha avuto esito negativo.

Test dell'API

I test delle API possono fare riferimento alla conferma del comportamento delle API fornite dal software o all'accesso alle API reali (possibilmente attive) per confermarne il comportamento. In entrambi i casi, questo tende a verificare le astrazioni tra i sistemi, ovvero il modo in cui comunicheranno tra loro, senza integrarli effettivamente insieme come in un test di integrazione.

Questi test possono fornire un prerequisito di base per i test di integrazione senza l'overhead associato all'esecuzione dei sistemi tra cui stai testando le connessioni. Tuttavia, i test dei sistemi reali possono essere imprecisi.

Altri tipi

Esistono vari altri approcci ai test che potrebbero essere utili, a seconda dell'origine. Ecco alcuni esempi interessanti:

  • Test manuali.
  • I test di accettazione, una sorta di test manuale reso popolare da Agile, confermano che il prodotto "soddisfa le esigenze dell'utente".
  • Il test del caos si riferisce all'inserimento di dati casuali per vedere cosa succede e assicurarsi che un sito non si arresti in modo anomalo se vengono inseriti dati errati.
  • I test di errori simulano intenzionalmente gli errori in sistemi complessi, ad esempio errori di rete, per garantire che il codice sottoposto a test risponda in modo controllato.
  • I test delle build confermano che gli artefatti di build di un codebase possono essere generati, verificando che esistano o quali siano i loro contenuti. Questo tipo di test può essere utile per controllare l'output di un CMS complesso.

Copertura codice

È possibile misurare la percentuale di codice testata da test automatici e segnalarla come una statistica nel tempo. Sconsigliamo di puntare a una copertura del 100% del codice, perché ciò può portare a overhead superfluo, nonché test semplici o mal progettati che non coprono in dettaglio i principali casi d'uso.

La copertura stessa può essere uno strumento utile anche quando scrivi o lavori ai test, in particolare i test di integrazione. La visualizzazione di una percentuale o di un'analisi riga per riga del codice testato in un singolo test ti consente di ottenere informazioni dettagliate su ciò che manca o su cosa può essere testato in seguito.

Risorse

Verifica le tue conoscenze

Quali dei seguenti sono tipi di test noti?

Test visivi
Test del caos
Test antincendio
Magari stai creando software per i vigili del fuoco.
Test di differenziazione
Test dello stress
Non lo abbiamo accennato qui, ma il test di stress o di carico è un tipo di sistemi di produzione di test per garantire che possano accettare una grande quantità di traffico. È più associato a una grande progettazione di sistemi che al test di codebase più tipici.