Test di un'API Node.js

introduzione

I test sono importanti; forniscono una protezione per le vostre applicazioni o API. Come principianti, è possibile non essere consapevoli della necessità di scrivere test che coprano le parti importanti di ciò che si sta costruendo. Eppure lo incontrerai mentre progredisci come sviluppatore.

In un precedente tutorial, hai imparato come creare un'API con Node.js. Se non l'hai fatto, ti suggerisco di farlo prima di continuare con questo. In questo tutorial, dovrai scrivere test per un'API costruita utilizzando Node.js ed Express. Alla fine di questo tutorial, saprai come funziona il test in Node.js e sarai in grado di creare API funzionali e testate.

Strumenti di test

Farai uso di Mocha, Expect e Supertest.

moca è un framework di test JavaScript che rende i test asincroni semplici e divertenti. La moka ha tantissime fantastiche funzionalità che puoi trovare sul sito web. Ne farai uso una manciata.

Aspettarsi è una libreria di asserzioni che ti rende facile fare affermazioni migliori. Vedrai come funziona. Supertest fornisce un'astrazione di alto livello per testare HTTP. Questo è necessario poiché testerai un'API.

Basta parlare, è tempo di scrivere del codice.

Impostazione del progetto

Ho un progetto di lista delle cose da fare già impostato per te. Il modello, il file di configurazione e parte dell'app.js sono già fatti per te. Vai su GitHub e clona il repository. O puoi semplicemente fare:

git clone https://github.com/izuchukwu1/node-todo-api.git

Il tuo pacchetto.json dovrebbe assomigliare a questo.

# package.json "name": "node-todo-api", "version": "1.0.0", "description": "", "main": "server.js", "scripts": " start ":" node server / server.js "," test ":" export NODE_ENV = test || SET \ "NODE_ENV = test \" && mocha server / ** / *. test.js "," test-watch " : "nodemon --exec 'npm test'", "motori": "nodo": "8.0.0", "parole chiave": [], "autore": "", "licenza": "ISC" , "dipendenze": "body-parser": "^ 1.17.2", "express": "^ 4.15.3", "lodash": "^ 4.17.4", "mongodb": "^ 2.2.29 "," mangusta ":" ^ 4.11.1 "," devDependencies ": " expect ":" ^ 1.20.2 "," mocha ":" ^ 3.4.2 "," nodemon ":" ^ 1.11.0 "," supertest ":" ^ 3.0.0 "

Ora esegui il comando per installare le dipendenze.

installazione di npm

Test richiesta POST

Per il tuo test, crea una nuova cartella chiamata test; questa cartella dovrebbe essere nel tuo server directory. Ora crea un nuovo file in cui scrivere il test. Nominare il file server.test.js.

In questo file, iniziare richiedendo i moduli installati. È inoltre necessario richiedere il file del server e il modello.

# server / test / server.test.js const expect = require ('expect') const request = require ('supertest') const ObjectId = require ('mongodb') const app = require ('./ ... / server ') const Todo = require (' ./ ... / models / todo ')

Devi avere alcune cose da fare che saranno usate durante i test. Ma queste cose da fare verranno eliminate dal database di test ogni volta che si esegue la suite di test. Per gestirlo, crea due test in questo modo.

# server / test / server.test.js const todos = [_id: new ObjectId (), testo: "Primo test todo", _id: nuovo ObjectId (), testo: "Secondo test todo", completato: true , completatoAt: 333] beforeEach ((done) => Todo.remove (). then (() => return Todo.insertMany (todos)). then (() => done ()) )

Il blocco precedente pulisce il tuo database Todo, quindi inserisce le cose da fare impostate sopra. Ciò garantisce di disporre di una quantità stabile di voci nel database in modo che i test non presentino problemi.

Fatto ciò, puoi scrivere il test per il INVIARE richiesta. Per il tuo INVIARE richiesta, scriverete due test. Il primo farà una richiesta per una cosa da fare valida e avrà successo. Il secondo farà una richiesta con un corpo non valido, e questo non dovrebbe creare una nuova cosa da fare.

Ecco come dovrebbe apparire il test.

# server / test / server.test.js Descrizione ('POST / todos', () => // 1 it ('dovrebbe creare un nuovo todo', (done) => let text = 'Test todo text' // 2 richiesta (app) // 3 .post ('/ todos') .send (text) .expect (200) .expect ((res) => expect (res.body.text) .toBe ( text)) .end ((err, res) => // 4 if (err) return done (err) Todo.find (text). then ((todos) => // 5 expect (todos.length) .toBe (1) expect (todos [0] .text) .toBe (text) done ()). catch ((e) => done (e)))) it ('dovrebbe non creare todo con dati del corpo non validi ', (done) => // 6 request (app) // 7 .post (' / todos ') .send () .expect (400) .end ((err, res) => if (err) return done (err) Todo.find (). then ((todos) => // 8 expect (todos.length) .toBe (2) done ()). catch ((e) => done (e)))))

Esegui il test usando il comando:

test di funzionamento npm

Dovrebbe fallire. Ecco cosa sta succedendo:

  1. Descrive il test.
  2. Crea una nuova cosa da fare e la salva come valore per il testo.
  3. Fai una richiesta POST al / Todos percorso della tua API, inviando il to-do creato come il corpo della richiesta. Si aspetta che il codice di stato per la richiesta sia 200 e il corpo della cosa da fare per eguagliare il valore di testo.
  4. Un errore viene restituito se ce n'è uno, e questo causerà la fine della richiesta. Quindi il prossimo blocco di codice non verrà eseguito. Se non si incontra un errore, il flusso continua.
  5. Viene fatta una richiesta al database per trovare la cosa da fare creata. Ci si aspetta che la lunghezza delle cose da fare nel database sia 1 e che il testo della cosa da fare sia uguale al valore del testo.
  6. Questo è il test eseguito con dati del corpo non validi.
  7. UN INVIARE richiesta è fatta al / Todos sentiero. Questa volta, stai inviando una richiesta senza corpo. Ti aspetti di ottenere un 400 richiesta. Non c'è bisogno di controllare il corpo come non lo si sta inviando. Se si verifica un errore, viene restituito e il codice smette di funzionare.
  8. Se non si incontra un errore, viene richiesta al database di verificare la lunghezza delle cose da fare. Ci aspettiamo che il database conterrà solo 2, che sono le cose da fare create all'inizio.

Per far passare questo test, vai al tuo server.js file e rilascia il codice necessario per la richiesta POST.

# server / server.js app.post ('/ todos', (req, res) => let todo = new Todo (text: req.body.text) todo.save (). then ((doc) => res.send (doc), (e) => res.status (400) .send (e)))

GET Request Test

Questo è semplice: il test dovrebbe restituire la lunghezza delle cose da fare disponibili nel database. Come già sapete, la lunghezza di ogni situazione dovrebbe essere 2. Perché? Hai indovinato. All'inizio della suite di test, hai creato un beforeeach blocco che pulisce il database e inserisce nuove cose da fare ogni volta che viene eseguita la suite di test.

Per verificare che la richiesta di ottenere tutte le cose da fare funzioni, ecco il codice per questo.

# server / test / server.test.js descrivi ('GET / todos', () => it ('dovrebbe ottenere tutti i todos', (done) => request (app) .get ('/ todos') .expect (200) .expect ((res) => expect (res.body.todos.length) .toBe (2)) .end (done)))

In quanto sopra, stai facendo un OTTENERE richiesta al / Todos sentiero. Questa volta, non stai passando nulla come corpo della richiesta perché è un OTTENERE richiesta. Si prevede di ottenere una risposta con il codice di stato di 200. Quindi ti aspetti che la durata delle cose da fare sia 2.

Quando esegui il test, dovresti ricevere un errore. Prova a far passare l'errore da solo.

Scommetto che l'hai fatto funzionare. Ecco il codice per far passare il test; confrontalo con la tua soluzione.

# server / server.js app.get ('/ todos', (req, res) => Todo.find (). then ((todos) => res.send (todos), (e) => res.status (400) .send (e)))

Quando un OTTENERE richiesta è fatta al / Todos percorso, vuoi trovare tutte le cose da fare nella raccolta Todo e restituirle come cose da fare. Aggiungere questo a server.js fa passare il test.

Quindi, scriverete tre test per il OTTENERE richiesta fatta per recuperare le cose da fare individuali. Il primo dovrebbe recuperare e restituire la cosa da fare. Il secondo e il terzo dovrebbero tornare 404 errore nei casi in cui la cosa da fare non viene trovata.

Apri il tuo server.test.js e creare un nuovo blocco descrittivo con il primo caso di test.

# server / server.test.js descrivi ('GET / todos /: id', () => it ('dovrebbe restituire todo doc', (done) => request (app) .get ('/ todos / $ todos [0] ._ id.toHexString () ') .expect (200) .expect ((res) => expect (res.body.todo.text) .toBe (todos [0] .text) ) .end (done))

Questo test fa a OTTENERE richiesta di recuperare la prima cosa da fare disponibile nel tuo database. Ti aspetti di ottenere un 200 codice di stato, quindi verifica che il valore testuale della cosa da fare sia uguale a quello creato.

Il prossimo test sembra così.

 ('dovrebbe restituire 404 se todo non viene trovato', (done) => let _id = new ObjectId ('5967989ee978311656e93a59') request (app) .get ('/ todos / $ todos / _id.toHexString () ') .expect (404) .end (done))

Qui stai cercando una cosa da fare usando un ID che non corrisponde all'ID di nessuna delle cose da fare salvate nel tuo database. Il test si aspetta che questa richiesta restituisca a 404 errore.

L'ultimo test è come il primo ma un po 'diverso; ecco come appare.

 ('dovrebbe restituire 404 per id non-oggetto', (done) => let hexId = '5967989ee978311656e93a5312' request (app) .get ('/ todos / $ todos / hexId') .expect (404). fine (fatto)))

Qui, crei un non valido ObjectId e prova a interrogare il database per ottenere una cosa che corrisponda al ObjectId creato. Il test si aspetta la richiesta di restituire a 404 errore. 

Quando si esegue il test, tutti dovrebbero fallire. Per farli passare, aggiungi il codice qui sotto al tuo server.js file.

# server / server.js app.get ('/ todos /: id', (req, res) => let id = req.params.id // 1 if (! ObjectId.isValid (id)) // 2 return res.status (404) .send ('ID non è valido') Todo.findById (id) .then ((todo) => if (! Todo) // 3 return res.status (404) .send () res.send (todo) // 4). catch ((e) => res.status (400) .send ()))
  1. Ottieni l'ID della cosa richiesta dai parametri.
  2. Controlla se l'ID è valido. Se l'ID non è valido, viene inviato un messaggio di errore.
  3. Se l'ID è valido, prova a trovare una cosa che corrisponde a quell'ID usando il findById metodo. Se non viene trovata nessuna cosa con quell'ID, a 404 errore viene inviato.
  4. Se viene trovata una cosa da fare, viene inviata la cosa da fare. Quindi si rileva qualsiasi errore che si verifica e lo invia.

Esegui il comando test ancora una volta e dovrebbe passare.

DELETE Test di richiesta

Il test per il tuo ELIMINA la richiesta sarà un po 'come quello che hai per la tua richiesta GET.

Innanzitutto, vuoi verificare che una cosa da fare sia cancellata.

# server / test / server.test.js descrivi ('DELETE / todos /: id', () => it ('dovrebbe eliminare un todo', (done) => let hexId = todos [0] ._ id .toHexString () // 1 richiesta (app) .delete ('/ todos / $ hexId') .expect (200) .expect ((res) => expect (res.body.todo._id) .toBe (hexId)) .end ((err, res) => // 2 if (err) return done (err)) Todo.findById (hexId) .then ((todo) => // 3 expect (todo.hexId) .toNotExist () done ()). catch ((e) => done (e)))

Ecco cosa sta succedendo sopra:

  1. Imposta l'id della cosa da fare su una variabile chiamata hexid. Successivamente, a ELIMINA la richiesta viene fatta al percorso della cosa da fare, usando l'ID. Ti aspetti di ottenere un 200 risposta, e la cosa da fare ottenuta per abbinare il valore di hexid.
  2. Se si verifica un errore, viene restituito.
  3. Se non ci sono errori, il test va oltre per interrogare il database usando l'ID salvato come valore di hexid. Dal ELIMINA la richiesta è stata inviata in precedenza, il test si aspetta che l'impegno corrispondente a tale ID non esista.

Successivamente, si desidera verificare che quando viene effettuata una richiesta per eliminare una cosa da fare che non esiste, la risposta contiene a 404 errore. È importante avere questo, in quanto non è possibile cancellare una cosa da fare due volte. Ecco come dovrebbe apparire il test per questo.

# server / test / server.test.js esso ('dovrebbe restituire 404 se todo non viene trovato', (done) => lasciare hexId = new ObjectId (). aHexString () request (app) .delete ('/ todos / $ todos / hexId ') .expect (404) .end (done))

Questo crea un ID per una cosa da fare che non esiste nel database. Poi un ELIMINA la richiesta è fatta per cancellare la cosa da fare. Si prevede che il test restituisca a 404 errore come la cosa da fare non esiste.

Vuoi testarlo a ELIMINA utilizzando un ID non valido restituisce a 404 errore, così.

# server / test / server.test.js ('dovrebbe restituire 404 per gli ID non oggetto', (done) => request (app) .delete ('/ todos / 123abc') .expect (404) .end (fatto) ) )

Per far passare il test, apri il tuo server.js e rilascia questo.

# server / server.js app.delete ('/ todos /: id', (req, res) => let id = req.params.id if (! ObjectId.isValid (id)) return res.status ( 404) .send () Todo.findByIdAndRemove (id) .then ((todo) => if (! Todo) return res.status (404) .send () res.send (todo)) .catch ((e) => res.status (400) .send ()))

Esegui il comando per testare:

test di funzionamento npm

E i tuoi test dovrebbero passare.

Conclusione

A questo punto, ora sai come configurare una suite di test durante la creazione di un'API utilizzando Node.js. Hai utilizzato Mocha, Expect e Supertest per testare un'API. Un vantaggio consiste nel fatto che non è necessario attivare sempre Postman durante la creazione dell'API. Con il tuo test, puoi sapere cosa è rotto.

Prima di concludere, si noti che JavaScript è diventato una delle lingue di fatto del lavoro sul web. Non è senza le sue curve di apprendimento, e ci sono un sacco di quadri e librerie per tenerti occupato, pure. Se stai cercando ulteriori risorse da studiare o da utilizzare nel tuo lavoro, dai un'occhiata a ciò che abbiamo a disposizione su Envato Market.

Usando ciò che ora sai, sei bravo a esplorare il mondo dei test.