Una guida pratica per testare le applicazioni React con Jest
Pubblicato: 2022-03-10In questo articolo, ti presenterò uno strumento di test React chiamato Jest, insieme alla popolare libreria Enzyme, progettata per testare i componenti React. Ti presenterò le tecniche di test di Jest, tra cui: esecuzione di test, test dei componenti React, test di snapshot e mocking. Se non conosci i test e ti stai chiedendo come iniziare, troverai utile questo tutorial perché inizieremo con un'introduzione ai test. Alla fine, sarai in grado di testare le applicazioni React utilizzando Jest ed Enzyme. Dovresti avere familiarità con React per seguire questo tutorial.
Una breve introduzione al test
Il test è una revisione riga per riga di come verrà eseguito il codice. Una suite di test per un'applicazione comprende vari bit di codice per verificare se un'applicazione viene eseguita correttamente e senza errori. Il test è utile anche quando vengono apportati aggiornamenti al codice. Dopo aver aggiornato un pezzo di codice, puoi eseguire un test per assicurarti che l'aggiornamento non interrompa la funzionalità già nell'applicazione.
Perché testare?
È bene capire perché facciamo qualcosa prima di farlo. Quindi, perché testare e qual è il suo scopo?
- Il primo scopo del test è prevenire la regressione. La regressione è la ricomparsa di un bug che era stato precedentemente corretto. Impedisce a una funzione di funzionare come previsto dopo che si verifica un determinato evento.
- I test garantiscono la funzionalità di componenti complessi e applicazioni modulari.
- Il test è necessario per l'efficacia delle prestazioni di un'applicazione software o di un prodotto.
Il test rende un'app più robusta e meno soggetta a errori. È un modo per verificare che il tuo codice esegua ciò che desideri e che la tua app funzioni come previsto per i tuoi utenti.
Esaminiamo i tipi di test e cosa fanno.
Prova unitaria
In questo tipo di test vengono testate singole unità o componenti del software. Un'unità può essere una singola funzione, metodo, procedura, modulo o oggetto. Uno unit test isola una sezione di codice e ne verifica la correttezza, al fine di convalidare che ciascuna unità del codice del software funzioni come previsto.
Nel test unitario, le singole procedure o funzioni vengono testate per garantire che funzionino correttamente e tutti i componenti vengono testati individualmente. Ad esempio, il test di una funzione o il corretto funzionamento di un'istruzione o di un ciclo in un programma rientrerebbero nell'ambito del test di unità.
Test dei componenti
Il test dei componenti verifica la funzionalità di una singola parte di un'applicazione. I test vengono eseguiti su ciascun componente in isolamento dagli altri componenti. In genere, le applicazioni React sono costituite da diversi componenti, quindi il test dei componenti si occupa di testare questi componenti individualmente.
Ad esempio, si consideri un sito Web che ha diverse pagine Web con molti componenti. Ogni componente avrà i suoi sottocomponenti. Il test di ciascun modulo senza considerare l'integrazione con altri componenti viene definito test dei componenti.
Test come questo in React richiedono strumenti più sofisticati. Quindi, avremmo bisogno di Jest e talvolta di strumenti più sofisticati, come Enzyme, di cui parleremo brevemente in seguito.
Prova istantanea
Un test di snapshot assicura che l'interfaccia utente (UI) di un'applicazione Web non cambi in modo imprevisto. Acquisisce il codice di un componente in un momento nel tempo, in modo da poter confrontare il componente in uno stato con qualsiasi altro stato possibile che potrebbe assumere.
Impareremo il test degli snapshot in una sezione successiva.
Vantaggi e svantaggi del test
Il test è ottimo e dovrebbe essere fatto, ma ha vantaggi e svantaggi.
Vantaggi
- Previene una regressione inaspettata.
- Consente allo sviluppatore di concentrarsi sull'attività corrente, piuttosto che preoccuparsi del passato.
- Consente la costruzione modulare di un'applicazione che altrimenti sarebbe troppo complessa da costruire.
- Riduce la necessità di verifica manuale.
Svantaggi
- È necessario scrivere più codice, nonché eseguire il debug e la manutenzione.
- Gli errori di test non critici potrebbero causare il rifiuto dell'app in termini di integrazione continua.
Introduzione a Jest
Jest è un delizioso framework di test JavaScript con particolare attenzione alla semplicità. Può essere installato con npm o Yarn. Jest rientra in una categoria più ampia di utilità note come test runners. Funziona benissimo per le applicazioni React, ma funziona benissimo anche al di fuori delle applicazioni React.
Enzyme è una libreria utilizzata per testare le applicazioni React. È progettato per testare i componenti e consente di scrivere asserzioni che simulano azioni che confermano se l'interfaccia utente funziona correttamente.
Jest ed Enzyme si completano a vicenda così bene, quindi in questo articolo utilizzeremo entrambi.
Processo di esecuzione di un test con Jest
In questa sezione installeremo Jest e scriveremo dei test. Se non conosci React, ti consiglio di utilizzare l'app Create React, perché è pronta per l'uso e viene fornita con Jest.
npm init react-app my-app
Abbiamo bisogno di installare Enzyme **** e enzyme-adapter-react-16
con react-test-renderer
(il numero dovrebbe essere basato sulla versione di React che stai usando).
npm install --save-dev enzyme enzyme-adapter-react-16 react-test-renderer
Ora che abbiamo creato il nostro progetto sia con Jest che con Enzyme, dobbiamo creare un file setupTest.js
nella cartella src
del progetto. Il file dovrebbe assomigliare a questo:
import { configure } from "enzyme"; import Adapter from "enzyme-adapter-react-16"; configure({ adapter: new Adapter() });
Questo importa Enzima e configura l'adattatore per eseguire i nostri test.
Prima di continuare, impariamo alcune nozioni di base. Alcune cose chiave sono usate molto in questo articolo e dovrai capirle.
-
it
ortest
Passeresti una funzione a questo metodo e il test runner eseguirebbe quella funzione come un blocco di test. -
describe
Questo metodo facoltativo serve per raggruppare un numero qualsiasi diit
o istruzioni ditest
. -
expect
Questa è la condizione che il test deve superare. Confronta il parametro ricevuto con il matcher. Ti dà anche accesso a una serie di abbinamenti che ti consentono di convalidare cose diverse. Puoi leggere di più a riguardo nella documentazione. -
mount
Questo metodo esegue il rendering del DOM completo, inclusi i componenti figlio del componente padre, in cui stiamo eseguendo i test. -
shallow
Questo rende solo i singoli componenti che stiamo testando. Non esegue il rendering dei componenti figlio. Questo ci consente di testare i componenti in isolamento.
Creazione di un file di prova
Come fa Jest a sapere cos'è un file di prova e cosa no? La prima regola è che tutti i file trovati in qualsiasi directory con il nome __test__
sono considerati un test. Se metti un file JavaScript in una di queste cartelle, Jest proverà a eseguirlo quando chiami Jest, nel bene e nel male. La seconda regola è che Jest riconoscerà qualsiasi file con il suffisso .spec.js
o .test.js
. Cercherà i nomi di tutte le cartelle e tutti i file nell'intero repository.
Creiamo il nostro primo test, per una mini-applicazione React creata per questo tutorial. Puoi clonarlo su GitHub. Esegui npm install
per installare tutti i pacchetti, quindi npm start
per avviare l'app. Controllare il file README.md
per ulteriori informazioni.
Apriamo App.test.js
per scrivere il nostro primo test. Innanzitutto, controlla se il nostro componente dell'app viene visualizzato correttamente e se abbiamo specificato un output:
it("renders without crashing", () => { shallow(<App />); }); it("renders Account header", () => { const wrapper = shallow(<App />); const welcome = <h1>Display Active Users Account Details</h1>; expect(wrapper.contains(welcome)).toEqual(true); });
Nel test precedente, il primo test, con shallow
, verifica se il nostro componente dell'app viene visualizzato correttamente senza arresti anomali. Ricorda che il metodo shallow
esegue il rendering di un solo componente, senza componenti figlio.
Il secondo test verifica se abbiamo specificato un output di tag h1
di "Visualizza account utente attivo" nel nostro componente dell'app, con un matcher Jest di toEqual
.
Ora, esegui il test:
npm run test /* OR */ npm test
L'output nel tuo terminale dovrebbe essere simile a questo:
PASS src/App.test.js √ renders without crashing (34ms) √ renders Account header (13ms) Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 11.239s, estimated 16s Ran all test suites related to changed files. Watch Usage: Press w to show more.
Come puoi vedere, il nostro test è passato. Mostra che abbiamo una suite di test denominata App.test.js
, con due test riusciti quando Jest è stato eseguito. Parleremo più avanti del test delle istantanee e vedrai anche un esempio di test fallito.
Saltare o isolare un test
Saltare o isolare un test significa che quando Jest viene eseguito, uno specifico test contrassegnato non viene eseguito.
it.skip("renders without crashing", () => { shallow(<App />); }); it("renders Account header", () => { const wrapper = shallow(<App />); const header = <h1>Display Active Users Account Details</h1>; expect(wrapper.contains(header)).toEqual(true); });
Il nostro primo test verrà saltato perché abbiamo utilizzato il metodo skip
per isolare il test. Quindi, non verrà eseguito né apporterà alcuna modifica al nostro test durante l'esecuzione di Jest. Solo il secondo verrà eseguito. Puoi anche usare it.only()
.
È un po' frustrante apportare modifiche a un file di test e quindi dover eseguire nuovamente manualmente npm test
. Jest ha una bella funzionalità chiamata modalità orologio, che controlla le modifiche ai file ed esegue i test di conseguenza. Per eseguire Jest in modalità orologio, puoi eseguire npm test -- --watch
o jest --watch
. Consiglierei anche di lasciare Jest in esecuzione nella finestra del terminale per il resto di questo tutorial.
Funzione beffarda
Un mock è un duplicato convincente di un oggetto o modulo senza alcun reale funzionamento interno. Potrebbe avere un minimo di funzionalità, ma rispetto alla cosa reale, è una presa in giro. Può essere creato automaticamente da Jest o manualmente.
Perché dovremmo deridere? La presa in giro riduce il numero di dipendenze, ovvero il numero di file correlati che devono essere caricati e analizzati quando viene eseguito un test. Quindi, l'uso di molti mock rende i test eseguiti più rapidamente.
Le funzioni fittizie sono anche conosciute come "spie", perché ti permettono di spiare il comportamento di una funzione che viene chiamata direttamente da qualche altro codice, invece di testare solo l'output.
Esistono due modi per deridere una funzione: creando una funzione simulata per usarla nel codice di test o scrivendo una simulazione manuale per sovrascrivere una dipendenza del modulo.
I mock manuali **** vengono utilizzati per escludere funzionalità con dati fittizi. Ad esempio, invece di accedere a una risorsa remota, come un sito Web o un database, potresti voler creare un mock manuale che ti consenta di utilizzare dati falsi.
Useremo una funzione mock nella prossima sezione.
Test dei componenti di reazione
La sezione unirà tutte le conoscenze che abbiamo acquisito finora per capire come testare i componenti React. Il test implica assicurarsi che l'output di un componente non sia cambiato inaspettatamente in qualcos'altro. Costruire i componenti nel modo giusto è di gran lunga il modo più efficace per garantire il successo dei test.
Una cosa che possiamo fare è testare gli oggetti di scena dei componenti, in particolare, verificare se gli oggetti di scena da un componente vengono passati a un altro. Jest e l'API Enzyme ci consentono di creare una funzione simulata per simulare se gli oggetti di scena vengono passati tra i componenti.
Dobbiamo passare le props dell'account utente dal componente App
principale al componente Account
. Dobbiamo fornire i dettagli dell'account utente Account
per rendere l'account attivo degli utenti. È qui che la presa in giro torna utile, consentendoci di testare i nostri componenti con dati falsi.
Creiamo un mock per gli oggetti di scena user
:
const user = { name: "Adeneye David", email: "[email protected]", username: "Dave", };
Abbiamo creato una funzione di simulazione manuale nel nostro file di test e l'abbiamo avvolta attorno ai componenti. Diciamo che stiamo testando un ampio database di utenti. Non è consigliabile accedere al database direttamente dal nostro file di prova. Invece, creiamo una funzione simulata, che ci consente di utilizzare dati falsi per testare il nostro componente.
describe(" ", () => { it("accepts user account props", () => { const wrapper = mount(<Account user={user} />); expect(wrapper.props().user).toEqual(user); }); it("contains users account email", () => { const wrapper = mount(<Account user={user} />); const value = wrapper.find("p").text(); expect(value).toEqual("[email protected]"); }); });
describe(" ", () => { it("accepts user account props", () => { const wrapper = mount(<Account user={user} />); expect(wrapper.props().user).toEqual(user); }); it("contains users account email", () => { const wrapper = mount(<Account user={user} />); const value = wrapper.find("p").text(); expect(value).toEqual("[email protected]"); }); });
Abbiamo due test sopra e utilizziamo un livello di describe
, che prende il componente da testare. Specificando i prop e i valori che ci aspettiamo vengano superati dal test, siamo in grado di procedere.
Nel primo test, controlliamo se i prop che abbiamo passato al componente montato sono uguali ai finti prop che abbiamo creato sopra.
Per il secondo test, passiamo i prop utente al componente Account
montato. Quindi, controlliamo se riusciamo a trovare l'elemento <p>
che corrisponde a quello che abbiamo nel componente Account
. Quando eseguiamo la suite di test, vedrai che il test viene eseguito correttamente.
Possiamo anche testare lo stato del nostro componente. Verifichiamo se lo stato del messaggio di errore è uguale a null:
it("renders correctly with no error message", () => { const wrapper = mount( ); expect(wrapper.state("error")).toEqual(null); });
it("renders correctly with no error message", () => { const wrapper = mount( ); expect(wrapper.state("error")).toEqual(null); });
In questo test, controlliamo se lo stato del nostro errore del componente è uguale a null, usando un matcher toEqual()
. Se viene visualizzato un messaggio di errore nella nostra app, il test avrà esito negativo durante l'esecuzione.
Nella prossima sezione, analizzeremo come testare i componenti React con il test degli snapshot, un'altra tecnica straordinaria.
Test di istantanee
Il test di snapshot acquisisce il codice di un componente in un determinato momento, per confrontarlo con un file di snapshot di riferimento archiviato insieme al test. Viene utilizzato per tenere traccia delle modifiche nell'interfaccia utente di un'app.
La rappresentazione del codice effettiva di uno snapshot è un file JSON e questo JSON contiene un record dell'aspetto del componente quando è stato creato lo snapshot. Durante un test, Jest confronta il contenuto di questo file JSON con l'output del componente durante il test. Se corrispondono, il test passa; se non lo fanno, il test fallisce.
Per convertire un wrapper Enzima in un formato compatibile con il test di snapshot Jest, dobbiamo installare enzyme-to-json
:
npm install --save-dev enzyme-to-json
Creiamo il nostro test snapshot. Quando lo eseguiamo per la prima volta, l'istantanea del codice di quel componente verrà composta e salvata in una nuova cartella __snapshots__
nella directory src
.
it("renders correctly", () => { const tree = shallow(<App />); expect(toJson(tree)).toMatchSnapshot(); });
Quando il test precedente viene eseguito correttamente, il componente dell'interfaccia utente corrente verrà confrontato con quello esistente.
Ora, eseguiamo il test:
npm run test
Quando la suite di test viene eseguita, una nuova istantanea verrà generata e salvata nella cartella __snapshots__
. Quando eseguiamo un test successivamente, Jest verificherà se i componenti corrispondono allo snapshot.
Come spiegato nella sezione precedente, il metodo shallow
del pacchetto Enzyme viene utilizzato per eseguire il rendering di un singolo componente e nient'altro. Non esegue il rendering dei componenti figlio. Piuttosto, ci offre un bel modo per isolare il codice e ottenere informazioni migliori durante il debug. Un altro metodo, denominato mount
, viene utilizzato per eseguire il rendering del DOM completo, inclusi i componenti figlio del componente padre, in cui stiamo eseguendo i test.
Possiamo anche aggiornare il nostro snapshot, apportiamo alcune modifiche al nostro componente per far fallire il nostro test, cosa che accadrà perché il componente non corrisponde più a quello che abbiamo nel file dello snapshot. Per fare ciò, cambiamo il tag <h3>
nel nostro componente da <h3> Loading...</h3>
a <h3>Fetching Users...</h3>
. Quando il test verrà eseguito, questo sarà ciò che otterremo nel terminale:
FAIL src/App.test.js (30.696s) × renders correctly (44ms) ● renders correctly expect(received).toMatchSnapshot() Snapshot name: `renders correctly 1 - Snapshot + Received
7 | it("renderizza correttamente", () => { 8 | const wrapper = superficiale( FAIL src/App.test.js (30.696s) × renders correctly (44ms) ● renders correctly expect(received).toMatchSnapshot() Snapshot name: `renders correctly 1 - Snapshot + Received
Visualizza i dettagli dell'account degli utenti attivi
- Caricamento in corso... + Recupero utenti...
); > 9 | Expect(toJson(wrapper)).toMatchSnapshot(); | ^ 10 | }); 11 | 12 | /* it("renderizza senza crash", () => { a Oggetto. (src/App.test.js:9:27) › 1 istantanea non riuscita. Riepilogo istantanee › 1 snapshot non riuscito da 1 test suite. Ispeziona le modifiche al codice o premi "u" per aggiornarle. Test Suite: 1 fallito, 1 totale Test: 1 fallito, 1 totale Istantanee: 1 non riuscita, 1 in totale Tempo: 92.274 secondi Ha eseguito tutte le suite di test relative ai file modificati. Utilizzo dell'orologio: premi w per visualizzare di più.
Se vogliamo che il nostro test superi, cambieremmo il test allo stato precedente o aggiorneremmo il file di snapshot. Nella riga di comando, Jest fornisce istruzioni su come aggiornare lo snapshot. Innanzitutto, premi w
nella riga di comando per mostrare di più, quindi premi u
per aggiornare lo snapshot.
› Press u to update failing snapshots.
Quando premiamo u
per aggiornare lo snapshot, il test passerà.
Conclusione
Spero che ti sia piaciuto lavorare con questo tutorial. Abbiamo appreso alcune tecniche di test Jest utilizzando la libreria di test degli enzimi. Ti ho anche presentato il processo di esecuzione di un test, test dei componenti di React, mocking e test di snapshot. Se hai domande, puoi lasciarle nella sezione commenti qui sotto e sarò felice di rispondere a tutte e risolvere qualsiasi problema con te.
Risorse e ulteriori letture
- Documentazione scherzosa
- Documentazione sugli enzimi
- "Come testare i componenti di React: la guida completa", Mohammad Iqbal, freeCodeCamp
- "Test di reazione con Jest ed Enzima", Dominic Fraser, CodeClan