Dove vengono eseguiti i test

I test automatici possono in genere essere eseguiti eseguendo uno script manualmente o utilizzando un supporto di un framework di test, spesso chiamato esecutore di test, per trovare ed eseguire i test. Tuttavia, non sempre è consigliabile eseguire gli script manualmente. Esistono vari modi per eseguire i test che possono fornire feedback e sicurezza in diversi punti durante il ciclo di vita dello sviluppo.

Script prerequisito

In genere, i progetti web dispongono di un file di configurazione (il relativo file package.json) impostato da npm, pnpm, Bun o simili. Questo file di configurazione contiene le dipendenze del progetto e altre informazioni, oltre agli script di supporto. Questi script di supporto potrebbero includere come creare, eseguire o testare il progetto.

All'interno di package.json, dovrai aggiungere uno script denominato test che descriva come eseguire i test. Questo è importante perché, quando utilizzi npm o uno strumento simile, lo script"test" ha un significato speciale. Questo script può puntare semplicemente a un singolo file che genera un'eccezione, ad esempio node tests.js, ma ti consigliamo di utilizzarlo per indicare un esecutore di test consolidato.

Se utilizzi Vitest come runner di test, il file package.json sarà simile al seguente:

{
  "name": "example-project",
  "scripts": {
    "start": "node server.js",
    "test": "vitest --run"
  }
}

L'esecuzione di npm test con questo file esegue una volta il set predefinito di test di Vitest. In Vitest, l'impostazione predefinita prevede di trovare tutti i file che terminano con ".test.js" o simili ed eseguirli. A seconda dell'esecutore di test scelto, il comando potrebbe essere leggermente diverso.

Abbiamo scelto di usare Vitest, un framework di test sempre più popolare, come esempi durante questo corso. Puoi scoprire di più su questa decisione in Vitest come runner di test. Tuttavia, è importante ricordare che i framework e i runner per i test, anche in più lingue, tendono ad avere un gergo comune.

Chiamata di prova manuale

L'attivazione manuale dei test automatici (come l'utilizzo di npm test nell'esempio precedente) può essere pratico mentre lavori attivamente su un codebase. Scrivere test per una funzionalità durante lo sviluppo della stessa può aiutarti a capire come dovrebbe funzionare la funzionalità: si tratta del concetto di sviluppo basato sui test (TDD).

I runner hanno in genere un breve comando che puoi richiamare per eseguire alcuni o tutti i tuoi test e possibilmente una modalità watcher che ripete i test quando li salvi. Sono tutte opzioni utili durante lo sviluppo di una nuova funzionalità e sono progettate per semplificare la scrittura di una nuova funzionalità, dei relativi test o di entrambi, il tutto con feedback rapido. Vitest, ad esempio, funziona in modalità watcher per impostazione predefinita: il comando vitest controlla le modifiche ed esegue nuovamente i test trovati. Ti consigliamo di lasciare aperta questa finestra in un'altra finestra mentre scrivi i test, in modo da poter ricevere rapidamente un feedback sui test man mano che li sviluppa.

Alcuni runner ti consentono anche di contrassegnare i test come only nel codice. Se il tuo codice include test only, questi vengono attivati solo quando esegui i test, rendendo lo sviluppo dei test più rapido e semplice da risolvere. Anche se tutti i test vengono completati rapidamente, l'utilizzo di only può ridurre il sovraccarico e rimuovere la distrazione dovuta all'esecuzione di test non correlati alla funzionalità o al test a cui stai lavorando.

Per i progetti di piccole dimensioni, in particolare quelli con un solo sviluppatore, potrebbe essere utile prendere l'abitudine di eseguire regolarmente l'intera suite di test del codebase. Ciò è particolarmente utile se i test sono di piccole dimensioni e vengono completati rapidamente (in non più di pochi secondi per tutti i test) in modo da assicurarti che tutto funzioni prima di proseguire.

Eseguire test nell'ambito della procedura di pre-invio o della revisione

Molti progetti scelgono di confermare che un codebase funzioni correttamente quando è necessario unire di nuovo il codice nel ramo main. Se non hai mai eseguito test, ma hai contribuito ai progetti open source in passato, probabilmente avrai notato che parte del processo di richiesta di pull (PR) conferma che tutti i test del progetto sono stati superati, il che significa che il tuo nuovo entusiasmante contributo non ha influito negativamente sul progetto esistente.

Se esegui i test localmente, il repository online del progetto (ad esempio GitHub o un altro servizio di hosting del codice) non saprà che i test hanno avuto esito positivo, quindi l'esecuzione dei test come attività di pre-invio chiarisce a tutti i collaboratori che tutto funziona.

GitHub, ad esempio, li fa riferimento come "controlli di stato" che possono essere aggiunti tramite azioni GitHub. Le azioni GitHub sono fondamentalmente una sorta di test: ogni passaggio deve avere esito positivo (non fallire, oppure generare un Error) affinché l'azione venga superata. Puoi applicare le Azioni a tutte le PR di un progetto e un progetto può richiedere il superamento delle azioni prima di contribuire al codice. L'azione Node.js predefinita di GitHub esegue npm test come uno dei passaggi.

Uno screenshot di un processo di test delle azioni GitHub.
Uno screenshot di un processo di test delle azioni di GitHub.

Questo approccio ai test tenta di garantire che il codebase sia sempre "verde" poiché non accetta codice che non esegue correttamente i test.

Esegui test nell'ambito dell'integrazione continua

Una volta accettato il PR verde, la maggior parte dei codebase esegue nuovamente test in base al ramo main del progetto, anziché al PR precedente. Ciò può accadere immediatamente o con cadenza regolare (ad esempio ogni ora o ogni notte). Questi risultati vengono spesso mostrati come parte di una dashboard di integrazione continua (CI) che mostra l'integrità complessiva del progetto.

Questo passaggio di CI potrebbe sembrare ridondante, soprattutto per i progetti con codebase di dimensioni ridotte, ovvero test superati durante la revisione, per cui dovrebbero essere superati non appena viene applicata una modifica. Tuttavia, questo non è sempre vero. I test potrebbero non riuscire improvvisamente, anche dopo aver generato risultati verdi. Alcuni dei motivi sono:

  • Diverse modifiche sono state accettate "contemporaneamente", a volte note come "racecondition" e si influenzano a vicenda in modi discreti e non testati.
  • I test non sono riproducibili oppure testano il codice "instabile": possono essere superati e avere esito negativo senza modifiche al codice.
    • Questo può accadere se dipendi da sistemi esterni al codebase. Per un proxy, immagina di eseguire un test se Math.random() > 0.05: questa operazione non andrà a buon fine in modo casuale il 5% delle volte.
  • Alcuni test sono troppo costosi o costosi da eseguire su ogni PR, come i test end-to-end (ulteriori informazioni al riguardo nei tipi di test automatici), e possono non funzionare nel tempo senza creare sempre avvisi.

Nessuno di questi problemi è impossibile da risolvere, ma vale la pena rendersi conto che i test e lo sviluppo del software in generale non saranno mai una scienza esatta.

Un intervallo al rollback

Quando i test vengono eseguiti nell'ambito dell'integrazione continua, anche quando i test vengono eseguiti come parte di un controllo dello stato, è possibile che la build risulti in uno stato "rosso" o in un altro stato che indica che i test non vanno a buon fine. Come accennato in precedenza, questo può accadere per una serie di motivi, tra cui condizioni di gara all'invio del test o test irregolari.

Per i progetti più piccoli, il tuo istinto potrebbe essere trattato come una crisi. Interrompere tutto, eseguire il rollback o ripristinare la modifica in questione e tornare allo stato valido noto. Questo può essere un approccio valido, ma è importante ricordare che i test (e il software in generale) sono un mezzo finale, non un obiettivo in sé. Probabilmente il tuo obiettivo è scrivere software, non far superare tutti i test. Puoi invece eseguire il rollback in avanti eseguendo la modifica che provoca un errore con un'altra modifica che corregge i test non riusciti.

D'altra parte, potresti aver visto o lavorato a grandi progetti che rimangono in uno stato perpetuo. O peggio ancora, il progetto di grandi dimensioni ha un test instabile che si interrompe abbastanza spesso da causare l'onere della sveglia negli sviluppatori. Questo è spesso un problema esistenziale che i leader devono risolvere: questi test potrebbero anche essere disattivati perché sono visti come "un ostacolo allo sviluppo".

Non esiste una soluzione rapida, ma può aiutare a diventare più sicuri durante l'esecuzione di test di scrittura (miglioramento delle competenze) e a ridurre l'ambito dei test (semplificazione) in modo che i fallimenti possano essere identificati più facilmente. Un maggior numero di test dei componenti o test di integrazione (maggiori sui tipi in Tipi di test automatici) può fornire una maggiore sicurezza rispetto a un enorme test end-to-end difficile da gestire e che prova a eseguire tutto contemporaneamente.

Risorse

Verifica le tue conoscenze

Qual è il nome dello script speciale cercato da npm e programmi simili durante il test?

check
test
pre-invio
verify