Cosa sono i test automatizzati?

Completato

In questa unità verranno fornite informazioni sui vantaggi dei test automatizzati e sui tipi di test che è possibile eseguire. Verranno inoltre descritte le caratteristiche dei test efficaci e alcuni strumenti disponibili.

Cosa sono i test automatizzati?

I test automatizzati prevedono l'uso di software per eseguire il codice e confrontare i risultati effettivi con quelli previsti. Si possono paragonare ai test esplorativi o manuali, per cui una persona solitamente segue le istruzioni di un piano di test per verificare che il software funzioni come previsto.

I test manuali presentano diversi vantaggi. Ma quando le dimensioni della base di codice aumentano, i test manuali di tutte le funzionalità (inclusi i casi limite) possono diventare ripetitivi, noiosi e soggetti a errori. I test automatizzati consentono di eliminare parte di questo carico di lavoro e permettono ai tester manuali di concentrarsi sul loro obiettivo principale, ovvero fare in modo che gli utenti finali possano utilizzare il software in modo ottimale.

La piramide di test

Per quanto riguarda i test automatizzati, è prassi comune separarli in livelli. Mike Cohn propone questo concetto, la piramide di test, nel suo libro Succeeding with Agile.

Diagram showing the test pyramid. The pyramid shows the unit test layer marked with callout 1, and UI layer tests marked with callout 2.

Sebbene si tratti di una versione semplicistica del modello di Cohn, il concetto illustra che la maggior parte degli sforzi si concentra sulla scrittura di test che verificano i livelli di base del software (callout 1 nella piramide), ad esempio funzioni, classi e metodi. Gli sforzi diminuiscono progressivamente man mano che le funzionalità vengono combinate, ad esempio a livello dell'interfaccia utente (callout 2 nella piramide). L'idea è che, se è possibile verificare che ogni componente di livello inferiore funzioni come previsto in isolamento, poi i test nei livelli superiori dovranno solo verificare la corretta interazione tra più componenti per ottenere il risultato previsto.

Quando è opportuno scrivere i test?

La risposta dipende principalmente da specifiche esigenze e dalle competenze nella scrittura di test.

Non è mai troppo tardi per aggiungere test per il codice già scritto e distribuito. Ciò vale soprattutto per le funzionalità che si interrompono spesso o che richiedono la maggior parte del lavoro del team di test.

Per quanto riguarda i test legati alle pipeline di integrazione continua e recapito continuo, due concetti di cui si sentirà parlare sono i test continui e lo spostamento a sinistra.

I test continui sono quelli che vengono eseguiti nelle prime fasi del processo di sviluppo, quando ogni modifica si sposta attraverso la pipeline. Spostamento a sinistra significa considerare la qualità del software e i test nelle primissime fasi del processo di sviluppo.

Ad esempio, gli sviluppatori aggiungono spesso test case mentre sviluppano le loro funzionalità ed eseguono l'intera suite di test prima di inviare la modifica alla pipeline. Questo approccio consente di assicurare che il comportamento della funzionalità che stanno sviluppando sia quello previsto, senza peraltro interrompere le funzionalità esistenti.

Ecco un breve video in cui Abel Wang, Cloud Advocate di Microsoft, spiega come assicurare la qualità in un piano DevOps.

Chiedi ad Abel

Per lo spostamento a sinistra è spesso necessario coinvolgere i tester nel processo di progettazione, ancora prima che venga scritto il codice per le funzionalità. Questo modello è diverso dal modello "handoff", in cui le nuove funzionalità vengono testate solo dopo la progettazione e la scrittura del software. Un bug individuato in ritardo nel processo può influire sulla pianificazione di recapito del team e i bug potrebbero essere individuati settimane o anche mesi dopo che lo sviluppatore ha originariamente compilato la funzionalità.

Il compromesso

I test automatizzati implicano un compromesso. Anche se i test automatizzati permettono ai tester di concentrarsi sulla verifica dell'esperienza dell'utente finale, è possibile che gli sviluppatori debbano dedicare più tempo alla scrittura e alla gestione del codice di test.

Tuttavia, lo scopo dei test automatizzati è assicurare che i tester ricevano solo codice di qualità ottimale, ovvero che funziona come previsto. Gli sviluppatori potranno quindi risparmiare tempo perché avranno meno bug da gestire ed eviteranno di dover riscrivere codice per eventuali casi limite non considerati inizialmente.

Altri vantaggi

La documentazione e la possibilità di eseguire più facilmente il refactoring del codice sono altri due vantaggi offerti dai test automatizzati.

Documentazione

I piani di test manuali possono servire da documentazione per descrivere il comportamento previsto del software e il motivo per cui esistono determinate funzionalità.

Anche i test automatizzati possono essere usati allo stesso scopo. Il codice dei test automatizzati è spesso in formato leggibile dall'utente. Gli input specificati rappresentano i valori che gli utenti potrebbero immettere. Ogni output associato specifica il risultato che gli utenti dovranno aspettarsi.

In realtà, molti sviluppatori seguono il metodo di sviluppo basato su test (TDD), scrivendo il codice di test prima di implementare una nuova funzionalità. L'idea è scrivere un set di test, definiti specifiche, che inizialmente non vengono superati. Quindi lo sviluppatore scrive in modo incrementale codice per implementare la funzionalità finché non vengono superati tutti i test. Le specifiche documentano i requisiti e il metodo di sviluppo basato su test assicura che venga scritta solo la quantità necessaria di codice per implementare la funzionalità.

Refactoring

Si supponga di avere una grande base di codice da sottoporre a refactoring per velocizzare l'esecuzione di determinati componenti. Come si può sapere se il refactoring non causerà l'interruzione di parti dell'applicazione?

I test automatizzati sono in effetti un tipo di contratto in cui vengono specificati gli input e i risultati previsti. Con un set di test superati, è possibile sperimentare ed eseguire più facilmente il refactoring del codice. Quando si apporta una modifica, è sufficiente eseguire i test e verificare che continuino a essere superati. Dopo aver raggiunto gli obiettivi di refactoring, è possibile inviare la modifica alla pipeline di compilazione in modo che risulti utile per tutti riducendo il rischio che si verifichino malfunzionamenti.

Quali tipi di test automatizzati sono disponibili?

Esistono molti tipi di test automatizzati, Ogni test ha uno scopo specifico. Ad esempio, è possibile eseguire test di sicurezza per verificare che solo gli utenti autorizzati possano accedere a un componente del software o a una delle relative funzionalità.

Quando si parla di integrazione continua e di pipeline di compilazione, ci si riferisce in genere ai test di sviluppo. I test di sviluppo sono quelli che è possibile eseguire prima di distribuire l'applicazione in un ambiente di test o di produzione.

Ad esempio, il lint test, un tipo di analisi statica del codice, controlla il codice sorgente per stabilire se è conforme alla guida di stile del team. Il codice formattato coerentemente è più facile da leggere e gestire.

In questo modulo si eseguiranno gli unit test e i test di code coverage.

Gli unit test verificano i componenti più fondamentali del programma o della libreria, ad esempio una singola funzione o un metodo. Si specificano uno o più input insieme ai risultati previsti. Il tester esegue ogni test e verifica se i risultati effettivi corrispondono a quelli previsti.

Si supponga ad esempio di avere una funzione che esegue un'operazione aritmetica che include la divisione. Si potrebbero specificare alcuni valori che si prevede vengano immessi dagli utenti, oltre a valori di casi limite come 0 e -1. Se l'input specificato genera un errore o un'eccezione, è possibile verificare se la funzione genera lo stesso errore.

I test di code coverage calcolano la percentuale di codice verificata dagli unit test. Possono includere diramazioni condizionali nel codice per assicurare che una funzione venga completamente verificata.

Una percentuale di code coverage più alta assicura una maggiore certezza che in seguito non verrà individuato un bug nel codice che non è stato completamente testato. Non è necessario raggiungere il 100% di code coverage. In effetti è possibile iniziare da una bassa percentuale, che però offre un punto di partenza da cui aggiungere altri test che verificano codice problematico o usato di frequente.

Mantenere l'isolamento degli unit test

Agli unit test vengono spesso associati termini come mock, stub e inserimento delle dipendenze.

Si tenga presente che gli unit test devono verificare una singola funzione o un singolo metodo e non l'interazione tra più componenti. Ma se è presente una funzione che chiama un database o un server Web, come è possibile gestirla?

Oltre a interrompere l'isolamento, la chiamata a un servizio esterno può rallentare le prestazioni. Se il database o il server Web diventa inattivo o altrimenti non disponibile, la chiamata può anche interrompere l'esecuzione dei test.

Applicando tecniche come il mocking e l'inserimento delle dipendenze, è possibile creare componenti che imitano questa funzionalità esterna. Un esempio verrà illustrato più avanti in questo modulo.

In seguito, è possibile eseguire i test di integrazione per verificare se l'applicazione funziona correttamente con un database o un server Web reale.

Come si definisce un test valido?

Man mano che si acquisisce esperienza nella scrittura di test personalizzati e nella lettura di test scritti da altri, si sarà in grado di identificare un test valido. Ecco alcune linee guida per iniziare:

  • Non eseguire test senza uno scopo: i test devono avere uno scopo e non possono essere semplicemente una voce da spuntare in un elenco di controllo. Scrivere test che verifichino se il codice fondamentale funziona come previsto e non interrompe le funzionalità esistenti.
  • Eseguire test brevi: i test devono essere completati il più rapidamente possibile, soprattutto durante le fasi di sviluppo e compilazione. Quando vengono eseguiti test ogni volta che una modifica si sposta nella pipeline, è infatti consigliabile evitare che creino colli di bottiglia.
  • Assicurarsi che i test siano ripetibili: le esecuzioni dei test devono generare gli stessi risultati ogni volta che vengono completate nel proprio computer, in quello di un collega o nella pipeline di compilazione.
  • Definire obiettivi specifici dei test: Un preconcetto comune è che i test siano destinati a coprire il codice scritto da altri. In genere, i test devono verificare solo il proprio codice. Se ad esempio si usa una raccolta di grafica open source nel progetto, non è necessario testarla.
  • Scegliere la granularità appropriata: Se ad esempio si eseguono unit test, un singolo test non dovrebbe combinare o verificare più funzioni o metodi. Testare ogni funzione separatamente e in seguito scrivere test di integrazione che verificano la corretta interazione tra più componenti.

Quali sono i tipi di strumenti di test disponibili?

Gli strumenti di test che possono essere utilizzati dipendono dal tipo di applicazione che si sta sviluppando e dal tipo di test che si vuole eseguire. Ad esempio, è possibile usare Selenium per eseguire test dell'interfaccia utente in molti tipi di Web browser e sistemi operativi.

Indipendentemente dal linguaggio in cui è scritta l'applicazione, sono disponibili numerosi strumenti di test.

Ad esempio, per le applicazioni Java si potrebbe scegliere Checkstyle per eseguire lint test e JUnit per gli unit test.

In questo modulo si userà NUnit per gli unit test perché è diffuso nella community .NET.

Verificare le conoscenze

1.

Secondo la piramide di test, a quali tipi di test è consigliabile dedicare la maggior parte del tempo?

2.

Spostamento a sinistra fa riferimento a:

3.

Quale delle affermazioni seguenti dimostra le procedure di test ottimali?