Esecuzione di unit test con Jest in progetti frontend

  • Jest offre un ambiente di unit testing potente e praticamente senza configurazione per progetti frontend che utilizzano JavaScript e React.
  • I test unitari migliorano l'individuazione precoce degli errori, documentano il codice e rendono il refactoring più sicuro.
  • Le funzionalità di mocking, test asincroni e copertura del codice di React Testing Library e Jest semplificano il test dei componenti e della logica di interfaccia.
  • L'integrazione dei test npm e dei report di copertura nel flusso di lavoro quotidiano aumenta significativamente la qualità e la stabilità del frontend.

scherzo

Se sviluppi interfacce in React o in altri framework di frontendPrima o poi ti rendi conto che affidarsi esclusivamente al principio "funziona sulla mia macchina" è come giocare con il fuoco. Una piccola modifica a un componente, un rapido refactoring o un aggiornamento delle dipendenze possono rompere parti dell'applicazione senza che tu te ne accorga... A meno che tu non abbia Un buon sistema di unit testing configurato con Jest.

L'ecosistema JavaScript moderno ha i test automatizzati nel suo DNA. Strumenti come Scherzare fallo Scrivi i test per il componenteL'utilizzo di funzioni e hook dovrebbe essere gestibile nel tuo lavoro quotidiano, anche se non sei un fanatico dei test. La chiave è avere una configurazione comoda, capire come scrivere i test e saper interpretare i risultati e la copertura per identificare le aree del codice che non vengono testate.

Perché eseguire unit test nei progetti frontend?

I test unitari sono piccoli test che convalidano parti specifiche del tuo codice (funzioni, componenti, hook, utility…). Nello sviluppo frontend, sono particolarmente utili perché l'interfaccia cambia frequentemente, ci sono logica di stato, eventi utente, chiamate asincrone, ecc. Senza una rete di sicurezza, ogni modifica è un azzardo.

Tra i vantaggi più evidenti dei test unitari vi sono: rilevamento precoce degli erroriInvece di scoprire i bug quando l'utente è già in produzione, li rilevi non appena salvi le modifiche ed esegui la suite di test, il che ti aiuta a comprendere meglio il ciclo di vita degli insettiQuesto fa risparmiare tempo, denaro e un sacco di grattacapi al team.

Un altro punto molto importante è che I test finiscono per funzionare come documentazione vivente.Osservare come è scritto un test per un componente o una funzione chiarisce come ci si aspetta che venga utilizzato, quali input accetta e quali risultati dovrebbe restituire. Nei progetti di grandi dimensioni, questo è di inestimabile valore per i nuovi membri del team.

Nel contesto di JavaScript e React, Scrivere test aiuta anche a modularizzare meglio il codicePer poter testare un componente separatamente, è necessario che sia ben isolato, con dipendenze chiare e responsabilità ben definite, il che si traduce in un frontend più gestibile a medio e lungo termine.

scherzo

Cos'è Jest e perché è così utilizzato nello sviluppo frontend?

Jest è un framework di test JavaScript originariamente sviluppato da FacebookProgettato per funzionare in modo ottimale con React, ma perfettamente valido per qualsiasi progetto JavaScript o TypeScript, sia lato client che lato server.

Uno dei suoi grandi punti di forza è la filosofia della “configurazione zero”In molti progetti, è sufficiente installarlo e aggiungere uno script al file package.json per iniziare a eseguire i test senza dover affrontare complessi file di configurazione. Questo lo rende particolarmente interessante negli ambienti frontend, dove sono già in uso molti strumenti.

Jest si integra di serie Caratteristiche principali per i progetti frontendEsecuzione rapida dei test, modalità watch che riesegue i test al rilevamento di modifiche, supporto molto pratico per il codice asincrono, mock e spy per simulare le dipendenze e generazione di report di copertura del codice senza dover ricorrere a strumenti esterni aggiuntivi.

Per i progetti frontend con React, Jest è quasi sempre combinato con Libreria di test di ReactQuesta libreria semplifica il test dei componenti attraverso il loro comportamento e il rendering, anziché essere eccessivamente vincolata all'implementazione interna. Grazie alla combinazione di questi due strumenti, è possibile soddisfare praticamente tutte le esigenze di test delle interfacce.

Libreria di test Jest e React per i componenti

Installazione di Jest e React Testing Library in un progetto frontend

Il primo passo per iniziare a usare Jest è aggiungerlo come dipendenza di sviluppo. nel tuo progetto. Se utilizzi npm, il comando tipico sarebbe:

npm install --save-dev jest

Se preferisci lavorare con il filatoÈ possibile installarlo con:

yarn add --dev jest

Nei progetti basati su React, è molto comune installare anche la React Testing Library., che è costituito da diversi pacchetti: la base @testing-library/react per i componenti, @testing-library/jest-dom per ulteriori matcher sul DOM e spesso @testing-library/user-event per simulare interazioni complesse dell'utente.

Una tipica configurazione React potrebbe essere simile a questa:

npm install –save-dev @testing-library/react @testing-library/jest-dom @testing-library/user-event

Con queste dipendenze configurate, il tuo ambiente è pronto per scrivere unit test incentrati sui componenti., eventi e risultati visibili all'utente, sempre affidandosi a Jest come motore principale di esecuzione dei test.

Configurazione base di Jest nel file package.json

Una volta installato Jest, è necessario indicare al progetto come verranno avviati i test.La prassi comune è quella di aggiungere uno script al file package.json per avere un semplice comando da eseguire dal terminale.

Un esempio minimo di configurazione potrebbe essere:

{ «script»: { «test»: «jest» } }

Con questo script puoi eseguire tutti i test del progetto semplicemente avviandolo:

test npm

oppure, se si usa il filato, con:

test del filato

Jest rileva automaticamente i file di test in base al loro nomePer impostazione predefinita, il programma cercherà i file con estensione .test.js o .spec.js nella struttura delle cartelle, quindi di solito non è necessario specificare manualmente i percorsi, a patto di rispettare queste convenzioni.

File di test ed esempi di Jest

Convenzione dei file: estensione .test.js e struttura dei test

Per consentire a Jest di riconoscere i tuoi test senza configurazioni aggiuntive, Si raccomanda vivamente di utilizzare l'estensione .test.js (oppure .test.ts se stai lavorando con TypeScript). Ad esempio, se hai un componente Button.jsx, un nome molto comune per il suo test potrebbe essere Button.test.js nella stessa directory o in una cartella di test separata.

Questa convenzione ha due chiari vantaggi:

  • Da un lato, Jest individua automaticamente i file da eseguire.
  • D'altro canto, chiunque si unisca al progetto per la prima volta sa immediatamente quali file contengono il codice di produzione e quali contengono i test.

I test sono definiti da la funzione di test o il suo alias essodove il primo argomento è una descrizione testuale di ciò che si sta verificando e il secondo è una funzione che esegue la logica di test. All'interno di tale funzione, le asserzioni vengono utilizzate tramite `expect` e i suoi vari matcher.

Nei componenti React la struttura è simileInvece di testare una funzione pura, si renderizza il componente con la React Testing Library, si cercano gli elementi sullo schermo (per testo, ruolo, etichette, ecc.) e si verifica che vengano visualizzati o reagiscano come previsto durante la simulazione delle interazioni dell'utente.

Scrivi il tuo primo test unitario con Jest

Per riportare tutto questo con i piedi per terra, Immagina una semplice funzione che somma due valoriIn un file chiamato sum.js, definisci la funzione sum(a, b) { return a + b; } ed esportala. Quindi, in sum.test.js, importa quella funzione e definisci un test con una descrizione chiara di cosa dovrebbe accadere.

Il corpo del test si limita all'esecuzione della funzione e alla convalida del risultato.Si chiama sum(1, 2) e si usa expect per indicare che il valore deve essere esattamente 3. Se la funzione smette di restituire quel risultato (a causa di un bug o di una modifica imprevista), Jest contrassegnerà il test come fallito.

Questo tipo di test, per quanto semplice possa sembrare, è alla base del test unitario.Ogni funzione o unità logica ha uno o più test che descrivono cosa dovrebbe fare in diversi scenari, in modo che qualsiasi deviazione dal comportamento previsto sia immediatamente evidente semplicemente eseguendo la suite di test.

Nei componenti frontend, l'approccio è altrettanto sempliceSi esegue il rendering del componente, si verifica cosa viene visualizzato, si simulano eventi come clic o scrittura nei campi di input e si convalida che lo stato risultante e il DOM corrispondano a quanto definito dal design funzionale dell'applicazione.

Man mano che il progetto cresce, potrai aggiungere ulteriori test per coprire i casi limiteInserimenti atipici, errori e situazioni meno ovvie, rafforzando l'affidabilità dell'applicazione e prevenendo regressioni quando si introducono nuove funzionalità.

Jest Matchers: diversi modi per verificare i risultati

Il cuore delle affermazioni in Jest è la funzione aspettativache è concatenato con diversi matcher per specificare i requisiti del valore ricevuto. A seconda di cosa stai testando, vorrai usarne uno piuttosto che un altro. Questi sono i matcher più pratici:

  • essere. Verifica l'uguaglianza rigorosa, che in JavaScript significa stesso valore e stesso tipo, molto utile per numeri, stringhe o valori booleani dove ci si aspetta una corrispondenza esatta. Se ti aspetti 3, non vuoi che arrivi "3".
  • a UgualeUtile quando si lavora con oggetti o array. Questo matcher confronta la struttura e il contenuto degli oggetti, consentendo di verificare che una funzione restituisca un oggetto con le proprietà e i valori corretti, anche se il riferimento interno non è lo stesso.
  • non. Se in qualsiasi momento è necessario assicurarsi che qualcosa NON accada, è possibile utilizzare la negazione `not`. Ad esempio, `expect(value).not.toBe(0)` chiarisce che un numero non deve essere zero, oppure `expect(array).not.toEqual([])` indica che non ci si aspetta un array vuoto.

Oltre a queste funzionalità di base, Jest offre molte altri sensali: per verificare che una funzione generi un errore, che un array contenga un elemento specifico, che una stringa corrisponda a un'espressione regolare o, con jest-dom nel caso di React, che un elemento DOM sia visibile, disabilitato, abbia un determinato testo, ecc.

Test asimmetrici JEST

Test asincroni in Jest: promise, async/await e callback

Il frontend moderno è pieno di operazioni asincroneRichieste HTTP, timer, interazioni utente che attivano aggiornamenti di stato, ecc. Ecco perché Jest integra diversi modi per lavorare comodamente con i test asincroni.

Il modo più pulito e comune per testare la logica asincrona è utilizzare async/awaitDichiari la tua funzione di test come asincrona, attendi che la promise che stai verificando si risolva e poi esegui le solite asserzioni con expect sul risultato ricevuto.

Ad esempio, potresti avere una funzione `fetchData` che restituisce una promise e scrivere un test asincrono che chiama `fetchData`, attende che venga risolta e verifica che i dati restituiti corrispondano a quanto previsto, che si tratti di un testo specifico o di un oggetto con una determinata struttura.

Jest supporta direttamente le promise senza async/awaitRestituisce la promise stessa dal test in modo che il framework sappia quando l'operazione è terminata. Inoltre, in casi più vecchi o molto specifici, consente l'uso di callback con un parametro `done` per indicare la fine del test.

Nel campo della libreria di test React, I test asincroni spesso combinano attese con findBy o waitForche consentono di attendere l'aggiornamento del DOM dopo una richiesta o un cambio di stato prima di effettuare le asserzioni pertinenti.

Scherzare in Jest: simulare moduli, funzioni e dipendenze

Un principio fondamentale del test unitario è isolare l'unità in provaQuesto significa che se una funzione o un componente dipende da servizi esterni (API, librerie di terze parti, moduli complessi, ecc.), è preferibile simulare tali comportamenti piuttosto che eseguirli effettivamente durante il test.

Jest facilita questo isolamento attraverso i mockCon jest.fn è possibile creare funzioni mock che registrano quante volte vengono chiamate, con quali argomenti o quale valore dovrebbero restituire. Questo è molto utile per testare le interazioni interne senza dover modificare il codice effettivo di tali servizi.

Quando è necessario fare un ulteriore passo avanti, jest.mock ti permette di sostituire interi moduliÈ possibile specificare che, durante l'importazione di un determinato file, Jest debba utilizzare un'implementazione fittizia che restituisca valori controllati, evitando, ad esempio, di inviare richieste HTTP reali ogni volta che viene eseguita la suite di test.

Nei componenti React, i mock vengono spesso utilizzati per simulare hook personalizzatiservizi o moduli dati che gestiscono l'archiviazione locale, l'analisi, ecc., mantenendo il test focalizzato sul comportamento del componente e non su quello delle sue dipendenze esterne.

Se usato correttamente, L'utilizzo di simulazioni (mocking) velocizza notevolmente l'esecuzione dei test. e consente di riprodurre facilmente scenari di errore, risposte anomale del server o stati atipici che sarebbero difficili da ottenere interagendo con servizi reali.

Organizzare e raggruppare i test con i blocchi descrive

Man mano che la tua suite di test cresce, hai bisogno mantenere un minimo di ordine Per evitare di perdersi tra centinaia di test sparsi in più file, Jest offre i blocchi come metodo naturale per raggruppare i test correlati.

Con descrivere puoi includere diversi test nello stesso contestoAd esempio, "operazioni aritmetiche" o "comportamento del componente di intestazione". All'interno del blocco, ogni test descrive un caso specifico, ma l'insieme si presenta come una sorta di storia coerente su quella parte del codice.

Questa organizzazione è utile sia per la lettura che per il debug.Quando qualcosa va storto, è più facile individuare il gruppo di test e capire quale parte del sistema è interessata, senza dover analizzare l'intero progetto.

Inoltre, descrive e si integra molto bene con gli hook del ciclo di vita di Jest, come beforeEach o afterEach, che consentono di preparare i dati o cancellare gli stati condivisi per tutti i test all'interno dello stesso blocco, evitando di duplicare la logica di inizializzazione in ogni singolo test.

Nei progetti frontend complessi, è comune avere una descrizione per ogni componente., se necessario suddiviso in descrizioni interne per diverse modalità, oggetti o flussi di interazione, il che trasforma il file di test in una mappa abbastanza chiara di tutto ciò che ci si aspetta da quel componente.

Utilizzo di npm testing e disciplina di esecuzione nel flusso di lavoro

Con la configurazione di base completata, Il comando npm test diventa il tuo alleato quotidianoL'esecuzione di questo processo prima di caricare le modifiche dovrebbe essere un gesto quasi automatico, come salvare il file o avviare il linter.

Molti team adottano la regola non scritta di non confermare le decisioni se i test falliscono.Questa pratica impedisce che il ramo principale del progetto si interrompa e garantisce una qualità minima in ogni merge o pull request integrata nel repository.

Jest offre anche una modalità interattiva molto utile attualmente in fase di sviluppoEseguendo `npm test` in modalità watch, il framework riesegue solo i test relativi ai file modificati, il che velocizza notevolmente il ciclo di test e correzione durante lo sviluppo di nuove funzionalità o la risoluzione di bug.

Integrazione di Jest in un sistema di integrazione continua (CI) come Azioni GitHub completare il cerchioOgni volta che qualcuno carica del codice nel repository remoto, il server CI esegue npm test e blocca l'integrazione se la suite fallisce, impedendo che gli errori si propaghino negli ambienti condivisi.

Copertura del codice: misurare quanto codice viene effettivamente testato

Avere dei test scritti non è sufficiente. È inoltre interessante sapere in che misura stiano coprendo il codice.A questo scopo, Jest integra un sistema di reportistica sulla copertura del codice che indica quali righe, funzioni e rami sono stati eseguiti durante i test.

Generare questi report è semplice come aggiungere il flag --coverage al comando di test.Ad esempio, puoi configurare lo script package.json come "test": "jest --coverage" oppure eseguire npm test --coverage quando desideri un report dettagliato.

Il risultato include Percentuali di copertura per file e a livello globalePotrai vedere quali file hanno una buona copertura e quali sono stati a malapena toccati durante i test, il che ti aiuterà a decidere dove vale la pena investire maggiori sforzi nella scrittura di ulteriori test.

Naturalmente, vale la pena ricordarlo Una copertura del 100% non garantisce l'assenza di erroriÈ possibile eseguire tutte le righe di codice con test poco impegnativi, quindi la qualità delle asserzioni è importante quanto, se non di più, del numero stesso.

Utilizzate la copertura del codice come indicatore approssimativo, in combinazione con le revisioni del codice e il buon senso.È un buon modo per mantenere un equilibrio tra lo sforzo di test e i benefici concreti per la stabilità del progetto.

Con tutto visto, Utilizzo di Jest e strumenti come React Testing Library nei progetti frontend Diventa una decisione abbastanza logicaConsente di verificare che ogni componente e funzione svolga correttamente il proprio compito, di eseguire facilmente i test con npm test, di monitorare la copertura del codice con –coverage e di mantenere una codebase solida in cui è molto più sicuro far evolvere il prodotto senza il timore di compromettere ciò che già funzionava.

Crea una pipeline CI/CD con GitHub Actions
Articolo correlato:
Come creare una pipeline CI/CD robusta con GitHub Actions