I test automatizzati ti aiutano a migliorare la qualità dell'app in diversi modi. Ad esempio, ti aiuta a eseguire la convalida, rilevare le regressioni e verificare la compatibilità. Una buona strategia di test ti consente di sfruttare i test automatizzati per concentrarti su un vantaggio importante: la produttività degli sviluppatori.
I team raggiungono livelli di produttività più elevati quando utilizzano un approccio sistematico al test, abbinato a miglioramenti dell'infrastruttura. In questo modo, riceverai tempestivamente un feedback sul comportamento del codice. Una buona strategia di test:
- Rileva i problemi il prima possibile.
- Esegue rapidamente.
- Fornisce indicazioni chiare quando è necessario risolvere un problema.
Questa pagina ti aiuterà a decidere quali tipi di test implementare, dove eseguirli e con quale frequenza.
La piramide dei test
Puoi classificare i test nelle applicazioni moderne in base alle dimensioni. I test di piccole dimensioni si concentrano solo su una piccola parte di codice, il che li rende veloci e affidabili. I test di grandi dimensioni hanno un ambito ampio e richiedono configurazioni più complesse e difficili da gestire. Tuttavia, i test di grandi dimensioni hanno una fedeltà maggiore* e possono rilevare molti più problemi in una sola volta.
*Fidelity si riferisce alla somiglianza dell'ambiente di runtime di test con l'ambiente di produzione.

La maggior parte delle app dovrebbe avere molti test di piccole dimensioni e relativamente pochi test di grandi dimensioni. La distribuzione dei test in ogni categoria deve formare una piramide, con i test più numerosi di piccole dimensioni che formano la base e i test meno numerosi di grandi dimensioni che formano la punta.
Ridurre al minimo il costo di un bug
Una buona strategia di test massimizza la produttività degli sviluppatori e riduce al minimo il costo della ricerca di bug.
Prendiamo in considerazione un esempio di strategia potenzialmente inefficiente. In questo caso, il numero di test per dimensione non è organizzato in una piramide. Ci sono troppi test end-to-end e troppo pochi test dell'interfaccia utente dei componenti:

Ciò significa che vengono eseguiti troppo pochi test prima dell'unione. Se è presente un bug, i test potrebbero non rilevarlo fino all'esecuzione dei test end-to-end notturni o settimanali.
È importante considerare le implicazioni di questo aspetto sul costo dell'identificazione e della correzione dei bug e perché è importante orientare le attività di test verso test più piccoli e frequenti:
- Quando il bug viene rilevato da un test unitario, in genere viene corretto in pochi minuti, quindi il costo è basso.
- Un test end-to-end potrebbe richiedere giorni per scoprire lo stesso bug. Ciò potrebbe coinvolgere più membri del team, riducendo la produttività complessiva e potenzialmente ritardando una release. Il costo di questo bug è più alto.
Detto questo, una strategia di test inefficiente è meglio di nessuna strategia. Quando un bug viene rilasciato in produzione, la correzione richiede molto tempo per essere implementata nei dispositivi degli utenti, a volte settimane, quindi il ciclo di feedback è il più lungo e costoso.
Una strategia di test scalabile
La piramide dei test è tradizionalmente suddivisa in tre categorie:
- Test delle unità
- Test di integrazione
- Test end-to-end.
Tuttavia, questi concetti non hanno definizioni precise, quindi i team potrebbero voler definire le proprie categorie in modo diverso, ad esempio utilizzando 5 livelli:

- Un test unitario viene eseguito sul computer host e verifica una singola unità funzionale di logica senza dipendenze dal framework Android.
- Esempio: verifica degli errori off-by-one in una funzione matematica.
- Un test dei componenti verifica la funzionalità o l'aspetto di un modulo o
componente indipendentemente dagli altri componenti del sistema. A differenza dei test
delle unità, l'area di superficie di un test dei componenti si estende ad astrazioni superiori
al di sopra di singoli metodi e classi.
- Esempio: Test screenshot per un pulsante personalizzato
- Un test delle funzionalità verifica l'interazione di due o più componenti o moduli indipendenti. I test delle funzionalità sono più grandi e complessi e
di solito operano a livello di funzionalità.
- Esempio: test del comportamento dell'interfaccia utente che verifica la gestione dello stato in una schermata
- Un test dell'applicazione verifica la funzionalità dell'intera applicazione
sotto forma di binario implementabile. Si tratta di test di integrazione di grandi dimensioni che
utilizzano un binario di cui è possibile eseguire il debug, ad esempio una build di sviluppo che può contenere hook di test,
come sistema in fase di test.
- Esempio: test del comportamento dell'interfaccia utente per verificare le modifiche alla configurazione in un test pieghevole, di localizzazione e di accessibilità
- Il test di una release candidate verifica la funzionalità di una build di rilascio.
Sono simili ai test dell'applicazione, tranne per il fatto che il binario dell'applicazione è
ridotto e ottimizzato. Si tratta di test di integrazione end-to-end di grandi dimensioni
che vengono eseguiti in un ambiente il più vicino possibile alla produzione senza
esporre l'app a account utente pubblici o backend pubblici.
- Esempio: Critical User Journey, test delle prestazioni
Questa classificazione tiene conto di fedeltà, tempo, ambito e livello di isolamento. Puoi avere diversi tipi di test su più livelli. Ad esempio, il livello di test dell'applicazione può contenere test di comportamento, screenshot e prestazioni.
Ambito |
Accesso di rete |
Esecuzione |
Tipo di build |
Ciclo di vita |
|
---|---|---|---|---|---|
Unità |
Metodo o classe singoli con dipendenze minime. |
No |
Locale |
Debuggable |
Pre-merge |
Componente |
Livello di modulo o componente Più corsi insieme |
No |
Locale |
Debuggable |
Pre-merge |
Funzionalità |
Livello della funzionalità Integrazione con componenti di proprietà di altri team |
Mocked |
Locale |
Debuggable |
Pre-merge |
Applicazione |
Livello di applicazione Integrazione con funzionalità e/o servizi di proprietà di altri team |
Simulato |
Emulator |
Debuggable |
Pre-fusione |
Candidato per la release |
Livello di applicazione Integrazione con funzionalità e/o servizi di proprietà di altri team |
Server di produzione |
Emulator |
Build di release ridotta |
Post-unione |
Decidere la categoria di test
Come regola generale, devi considerare il livello più basso della piramide che può fornire al team il giusto livello di feedback.
Ad esempio, considera come testare l'implementazione di questa funzionalità: la UI di un flusso di accesso. A seconda di ciò che devi testare, scegli categorie diverse:
Materia in fase di test |
Descrizione di ciò che viene testato |
Categoria di test |
Esempio di tipo di test |
---|---|---|---|
Logica di convalida del modulo |
Una classe che convalida l'indirizzo email rispetto a un'espressione regolare e verifica che il campo della password sia stato compilato. Non ha dipendenze. |
Test delle unità |
|
Comportamento dell'interfaccia utente del modulo di accesso |
Un modulo con un pulsante che viene attivato solo dopo la convalida del modulo |
Test dei componenti |
Test del comportamento dell'interfaccia utente in esecuzione su Robolectric |
Aspetto dell'interfaccia utente del modulo di accesso |
Un modulo che segue una specifica UX |
Test dei componenti |
|
Integrazione con Auth Manager |
L'interfaccia utente che invia le credenziali a un gestore dell'autenticazione e riceve risposte che possono contenere errori diversi. |
Test delle funzionalità |
|
Finestra di dialogo di accesso |
Una schermata che mostra il modulo di accesso quando viene premuto il pulsante di accesso. |
Test delle applicazioni |
Test del comportamento dell'interfaccia utente in esecuzione su Robolectric |
Critical User Journey: accesso |
Un flusso di accesso completo che utilizza un account di test su un server di staging |
Candidato per la release |
Test end-to-end del comportamento della UI di Compose in esecuzione sul dispositivo |
In alcuni casi, l'appartenenza di un elemento a una categoria o a un'altra può essere soggettiva. Esistono altri motivi per cui un test viene spostato verso l'alto o verso il basso, ad esempio costo dell'infrastruttura, instabilità e tempi di test lunghi.
Tieni presente che la categoria di test non determina il tipo di test e non tutte le funzionalità devono essere testate in ogni categoria.
Anche i test manuali possono far parte della tua strategia di test. In genere, i team addetti al QA eseguono test di Release Candidate, ma possono essere coinvolti anche in altre fasi. Ad esempio, test esplorativi per bug in una funzionalità senza uno script.
Infrastruttura di test
Una strategia di test deve essere supportata da infrastrutture e strumenti per aiutare gli sviluppatori a eseguire continuamente i test e applicare regole che garantiscano il superamento di tutti i test.
Puoi classificare i test in base all'ambito per definire quando e dove eseguire quali test. Ad esempio, seguendo il modello a 5 livelli:
Categoria |
Ambiente (dove) |
Trigger (quando) |
---|---|---|
Unità |
[Locale][4] |
Ogni commit |
Componente |
Locale |
Ogni commit |
Funzionalità |
Locale ed emulatori |
Pre-merge, prima di unire o inviare una modifica |
Applicazione |
Locale, emulatori, 1 smartphone, 1 pieghevole |
Post-fusione, dopo la fusione o l'invio di una modifica |
Candidato per la release |
8 smartphone diversi, 1 pieghevole, 1 tablet |
Pre-lancio |
- I test Unit e Component vengono eseguiti sul sistema di integrazione continua per ogni nuovo commit, ma solo per i moduli interessati.
- Tutti i test Unit, Component e Feature vengono eseguiti prima di unire o inviare una modifica.
- I test dell'applicazione vengono eseguiti dopo l'unione.
- I test della Release Candidate vengono eseguiti ogni notte su uno smartphone, un dispositivo pieghevole e un tablet.
- Prima di una release, i test Release Candidate vengono eseguiti su un numero elevato di dispositivi.
Queste regole possono cambiare nel tempo quando il numero di test influisce sulla produttività. Ad esempio, se sposti i test a una cadenza notturna, potresti ridurre i tempi di compilazione e test dell'integrazione continua, ma potresti anche prolungare il ciclo di feedback.