Pour tester un gestionnaire Express, il est utile de savoir comment réussir à simuler/stub ledemande
etréponse
objets. Les exemples suivants seront écrits à la fois en utilisant Jest et sinon (fonctionnant en AVA).
La raison en est la suivante. Jest est un framework de test « tout-en-un » très populaire. Sinon est l'un des « espions, stubs et simulations de tests autonomes pour JavaScript » les plus populaires qui « fonctionne avec n'importe quel framework de tests unitaires ».
L'approche détaillée dans cet article portera sur la manière de tester les gestionnaires indépendamment de l'instance de l'application Express en les appelant directement avec une requête simulée (demande
) et la réponse (rés
) objets. Il ne s’agit que d’une seule approche pour tester les gestionnaires et middleware Express. L'alternative consiste à lancer le serveur Express (idéalement en mémoire à l'aide de SuperTest). J'explique plus en détail comment y parvenir"Tester une application Express avec SuperTest, Moxios et Jest".
L'un des grands progrès conceptuels pour tester les applications Express avec une requête/réponse simulée est de comprendre comment simuler une API chaînée, par exemple.res.status(200).json({ foo: 'bar' })
.
Ceci est réalisé en renvoyant lerés
instance de chacune de ses méthodes :
const réponse simulée = () => { const rés = {} ; // remplace ce qui suit () => res // avec votre stub/mock de fonction de votre choix // s'assurant qu'ils renvoient toujours `res` rés.statut = () => rés; rés.json = () => rés; retour rés;} ;
Voir le référentiel avec des exemples et l'application de travail surgithub.com/HugoDF/mock-express-request-response.
Table des matières:
Table des matières
Stubs et simulations : Jest.fn vs sinon
est.fn
etsinon.stub
ont le même rôle. Ils renvoient tous deux un mock/stub pour une fonction. Cela signifie simplement une fonction qui rappelle des informations sur ses appels, par exemple. combien de fois et avec quels arguments il a été appelé.
La maquette Jest est étroitement intégrée au reste du framework. Cela signifie que nous pouvons avoir des assertions qui ressemblent à ce qui suit :
test('jest.fn rappelle comment il a été appelé', () => { const se moquer = Est.fn(); se moquer('un', 'b', 'c'); attendre(se moquer).toHaveBeenCalledTimes(1); attendre(se moquer).toHaveBeenCalledWith('un', 'b', 'c');});
Sinon est « juste » une bibliothèque d'espions/stubs/mocks, cela signifie que nous avons besoin d'un exécuteur de test séparé, l'exemple suivant est équivalent au précédent de Jest mais écrit en utilisant AVA :
const test = exiger('ava');const sinon = exiger('sinon');test('sinon.stub rappelle comment il a été appelé', t => { const se moquer = sinon.bout(); se moquer('un', 'b', 'c'); t.vrai(se moquer.appelé); t.vrai(se moquer.appeléAvec('un', 'b', 'c'));});
Se moquer/stubbing d'une API chaînée : réponse express
L’API Express User-Land est basée sur un middleware. Un middleware qui prend une requête (généralement appelédemande
), une réponse (généralement appeléerés
) et un next (appeler le middleware suivant) comme paramètres.
Un « gestionnaire de route » est un middleware qui a tendance à ne pas appelersuivant
, cela entraîne généralement l'envoi d'une réponse.
Un exemple de gestionnaires de routes est le suivant (dans express-handlers.js).
Dans cet exempledemande de session
est généré parsessions-client
, un middleware de Mozilla qui définit un cookie crypté sur le client (à l'aide d'unSet-Cookie
). Cela dépasse la portée de cet article. À toutes fins utiles, nous pourrions accéder/écrire à tout autre ensemble de propriétés de requête/réponse.
asynchrone fonction Se déconnecter(demande, rés) { demande.session.données = nul; retour rés.statut(200).json();}asynchrone fonction vérifierAuth(demande, rés) { si (!demande.session.données) { retour rés.statut(401).json(); } const { nom d'utilisateur } = demande.session.données; retour rés.statut(200).json({ nom d'utilisateur });}module.exportations = { Se déconnecter, vérifierAuth} ;
Ils sont consommés en étant « montés » sur une application Express (application
) instance (dans app.js) :
const exprimer = exiger('exprimer');const application = exprimer();const { Se déconnecter, vérifierAuth } = exiger('./express-handlers.js');application.obtenir('/session', vérifierAuth);application.supprimer('/session', Se déconnecter);
Pour que le code ci-dessus fonctionne de manière intégrée, nous devons égalementapp.use
lesessions-client
paquet comme ça. Notez que leNom du cookie
est important puisque c'est la propriété sous laquelle la session est définie sur ledemande
objet.
Nous ajoutons également leexpress.json
middleware (Express 4.16+), qui fonctionne comme celui de l'analyseur de corps.json()
option c'est à dire. il analyse les corps JSON et stocke la sortie danscorps requis
.
const exprimer = exiger('exprimer');const application = exprimer();const session = exiger('sessions-client');application.utiliser(exprimer.json());application.utiliser(session({ secrète: processus.env.SESSION_SECRET || 'mon-super-secret', Nom du cookie: 'session', durée: 60 * 60 * 1000 // 1 heure}));const { Se déconnecter, vérifierAuth } = exiger('./express-handlers.js');application.obtenir('/session', vérifierAuth);application.supprimer('/session', Se déconnecter);
Demande de moquerie/stubbing (une simple requête Express) avec Jest ou sinon
Une fonction mockRequest doit renvoyer un objet compatible avec la requête, qui est un simple objet JavaScript. Il pourrait ressembler à ce qui suit, en fonction des propriétés dedemande
le code testé utilise. Notre code accède uniquementreq.session.data
, ça veut dire qu'il attenddemande
avoir unsession
propriété qui est un objet afin qu'il puisse tenter d'accéder aureq.session.data
propriété.
const mockRequest = (données de session) => { retour { session: { données: données de session }, } ;} ;
Puisque ce qui précède ne concerne que les données, il n'y a aucune différence entre s'en moquer dans Jest ou utiliser sinon et le lanceur de test de votre choix (Mocha, AVA, tape, Jasmine…).
Résolution moqueuse/stubbing (une simple réponse express) avec Jest
Une fonction mockResponse ressemblerait à ce qui suit, notre code testé appelle uniquementstatut
etjson
les fonctions. Le problème que nous rencontrons est que les appels s’enchaînent. Cela signifie questatut
,json
et autrerés
(Réponse express) renvoient lerés
objet lui-même.
Cela signifie qu'idéalement, notre simulation se comporterait de la même manière :
const réponse simulée = () => { const rés = {} ; rés.statut = Est.fn().mockReturnValue(rés); rés.json = Est.fn().mockReturnValue(rés); retour rés;} ;
Nous exploitonsest.fn
c'estmockReturnValue
méthode pour définir la valeur de retour des deuxstatut
etjson
à l'instance de réponse fictive (rés
) ils sont prêts.
Résolution moqueuse/stubbing (une simple réponse express) avec sinon
Le sinon équivalent à ce qui précède (avec une explication similaire) suit. Avec sinon, nous devons explicitementexiger
car il s'agit d'une bibliothèque autonome (c'est-à-dire non injectée par des frameworks de test).
Les talons Sinon ont unRetour
méthode qui se comporte comme lamockReturnValue
Méthode de simulation de plaisanterie. Il définit la valeur de retour du stub.
Lestatut
etjson
méthodes sur notre instance de réponse fictive (rés
) renvoie l'instance de réponse (rés
) lui-même.
const sinon = exiger('sinon');const réponse simulée = () => { const rés = {} ; rés.statut = sinon.bout().Retour(rés); rés.json = sinon.bout().Retour(rés); retour rés;} ;
Tester un gestionnaire qui lit depuisdemande
et envoie unrés
en utilisant status et json()
LevérifierAuth
le gestionnaire lit à partir dedemande
et envoie unrés
en utilisantstatut()
etjson()
.
Il contient la logique suivante, sisession.data
n'est pas défini, la session n'est pas définie et donc l'utilisateur n'est pas authentifié, il envoie donc un401 Non autorisé
statut avec un corps JSON vide. Sinon, il reflète la partie du contenu de la session (juste lenom d'utilisateur
) en réponse JSON avec un code d'état 200.
Voici le code testé (dans express-handlers.js) :
asynchrone fonction vérifierAuth(demande, rés) { si (!demande.session.données) { retour rés.statut(401).json(); } const { nom d'utilisateur } = demande.session.données; retour rés.statut(200).json({ nom d'utilisateur });}
Nous devons tester deux chemins : l’un menant à un 401 et l’autre menant à un 200.
Voir un instantané de ce code sur GitHubgithub.com/HugoDF/mock-express-request-response/releases/tag/check-auth-tests(cliquez sur le commit sha pour le diff pour ce changement de version).
En utilisant lemockRequest
etréponse simulée
nous avons défini précédemment, nous définirons une requête qui n'a pas de données de session (pour 401) et qui a des données de session contenant le nom d'utilisateur (pour 200). Ensuite, nous vérifierons celastatut requis
est appelé avec 401 et 200 respectivement. Dans le cas 200, nous vérifierons également queres.json
est appelé avec la bonne charge utile ({ nom d'utilisateur }
).
Dans Jest (voir express-handlers.jest-test.js) :
décrire('vérifierAuth', () => { test('devrait 401 si les données de session ne sont pas définies', asynchrone () => { const demande = mockRequest(); const rés = réponse simulée(); attendre vérifierAuth(demande, rés); attendre(rés.statut).toHaveBeenCalledWith(401); }); test('devrait 200 avec le nom d'utilisateur de la session si les données de session sont définies', asynchrone () => { const demande = mockRequest({ nom d'utilisateur: 'hugo' }); const rés = réponse simulée(); attendre vérifierAuth(demande, rés); attendre(rés.statut).toHaveBeenCalledWith(200); attendre(rés.json).toHaveBeenCalledWith({ nom d'utilisateur: 'hugo' }); });});
Les mêmes tests utilisant sinon + AVA (dans express-handlers.sinon-test.js) :
test('checkAuth > devrait 401 si les données de session ne sont pas définies', asynchrone (t) => { const demande = mockRequest(); const rés = réponse simulée(); attendre vérifierAuth(demande, rés); t.vrai(rés.statut.appeléAvec(401));});test('checkAuth > devrait 200 avec le nom d'utilisateur de la session si les données sont définies', asynchrone (t) => { const demande = mockRequest({ nom d'utilisateur: 'hugo' }); const rés = réponse simulée(); attendre vérifierAuth(demande, rés); t.vrai(rés.statut.appeléAvec(200)); t.vrai(rés.json.appeléAvec({ nom d'utilisateur: 'hugo' }));});
Voir un instantané de ce code sur GitHubgithub.com/HugoDF/mock-express-request-response/releases/tag/check-auth-tests(cliquez sur le commit sha pour le diff pour ce changement de version).
Tester un gestionnaire qui écrit dansdemande
et envoie unrés
en utilisant status et json()
LeSe déconnecter
le gestionnaire écrit dans req (il définitreq.session.data
ànul
) et envoie une réponse en utilisantres.statut
etres.json
. Voici le code en cours de test.
asynchrone fonction Se déconnecter(demande, rés) { demande.session.données = nul; retour rés.statut(200).json();}
Il n'a pas de logique de branchement, mais nous devrions le testersession.data
est réinitialisé et une réponse est envoyée dans 2 tests distincts. Voir un instantané de ce code sur GitHubgithub.com/HugoDF/mock-express-request-response/releases/tag/logout-tests(cliquez sur le commit sha pour le diff pour ce changement de version).
En plaisantant, avec lemockRequest
etréponse simulée
fonctions (dans express-handlers.jest-test.js) :
décrire('Se déconnecter', () => { test('devrait définir session.data sur null', asynchrone () => { const demande = mockRequest({ nom d'utilisateur: 'hugo' }); const rés = réponse simulée(); attendre Se déconnecter(demande, rés); attendre(demande.session.données).êtreNull(); }); test('devrait 200', asynchrone () => { const demande = mockRequest({ nom d'utilisateur: 'hugo' }); const rés = réponse simulée(); attendre Se déconnecter(demande, rés); attendre(rés.statut).toHaveBeenCalledWith(200); });});
Dans AVA + sinon en utilisant les fonctions mockRequest et mockResponse (dans express-handlers.sinon-test.js) :
test('déconnexion> devrait définir session.data sur null', asynchrone (t) => { const demande = mockRequest({ nom d'utilisateur: 'hugo' }); const rés = réponse simulée(); attendre Se déconnecter(demande, rés); t.est(demande.session.données, nul);});test('déconnexion > devrait 200', asynchrone (t) => { const demande = mockRequest({ nom d'utilisateur: 'hugo' }); const rés = réponse simulée(); attendre Se déconnecter(demande, rés); t.vrai(rés.statut.appeléAvec(200));});
Voir un instantané de ce code sur GitHubgithub.com/HugoDF/mock-express-request-response/releases/tag/logout-tests(cliquez sur le commit sha pour le diff pour ce changement de version).
Un scénario moqueur de demande/réponse de gestionnaire complexe : une demande de connexion avec un corps
Notre gestionnaire de connexion fait le gros du travail dans l’application. C'est dedansexpress-handlers.js
et contient la logique suivante.
Le gestionnaire de connexion vérifie d'abord que le contenu decorps requis
et 400s si l'un d'eux manque (ce seront nos 2 premiers tests).
Le gestionnaire de connexion tente ensuite deobtenirUtilisateur
pour le nom d'utilisateur donné, s'il n'y a pas un tel utilisateur, c'est 401 (ce sera notre 3ème test).
Ensuite, le gestionnaire de connexion compare le mot de passe de la requête avec la version hachée/salée provenant deobtenirUtilisateur
sortie, si cette comparaison échoue, c'est 401 (ce sera notre 4ème test).
Enfin, si le nom d'utilisateur/mot de passe sont valides pour un utilisateur, le gestionnaire de connexion définit session.data sur{ nom d'utilisateur }
et envoie une réponse 201 (ce sera notre 5ème test).
Le dernier test (que je n'ai pas implémenté) qui aurait du sens est de vérifier que le gestionnaire envoie un 500 si une erreur survient lors de son exécution (par exemple.obtenirUtilisateur
lance).
Voir un instantané du code sur GitHubgithub.com/HugoDF/mock-express-request-response/releases/tag/login-tests(cliquez sur le commit sha pour le diff pour ce changement de version).
Les fonctions de connexion sont les suivantes, pour des raisons de lisibilité, j'ai omisobtenirUtilisateur
.obtenirUtilisateur
est implémenté dans tous les cas sous la forme d'une recherche de tableau codée en dur, alors que dans votre application, il s'agira d'une base de données ou d'un appel d'API (sauf si vous utilisez oAuth).
const bcrypt = exiger('bcrypt');asynchrone fonction se connecter(demande, rés) { essayer { const { nom d'utilisateur, mot de passe } = demande.corps; si (!nom d'utilisateur || !mot de passe) { retour rés.statut(400).json({ message: 'le nom d'utilisateur et le mot de passe sont requis' }); } const utilisateur = obtenirUtilisateur(nom d'utilisateur); si (!utilisateur) { retour rés.statut(401).json({ message: "Aucun utilisateur avec le nom d'utilisateur correspondant" }); } si (!(attendre bcrypt.comparer(mot de passe, utilisateur.mot de passe))) { retour rés.statut(401).json({ message: 'Mauvais mot de passe' }); } demande.session.données = { nom d'utilisateur } ; retour rés.statut(201).json(); } attraper (e) { console.erreur(`Erreur lors de la connexion de "${demande.corps.nom d'utilisateur}" :${e.empiler}`); rés.statut(500).json({ message: e.message }); }}
Il se consomme, en étant « monté » sur l’application Express enapp.js
:
application.poste('/session', se connecter);
Pour pouvoir tester la fonction de connexion, nous devons étendre lamockRequest
fonction, elle renvoie toujours un simple objet JavaScript donc il n'y a pas de différence entre notre version Jest et AVA + sinon :
const mockRequest = (données de session, corps) => ({ session: { données: données de session }, corps,});
Voir un instantané du code sur GitHubgithub.com/HugoDF/mock-express-request-response/releases/tag/login-tests(cliquez sur le commit sha pour le diff pour ce changement de version).
Tests pour le gestionnaire de connexion utilisant dans Jest
Note:Il y a un grand mur de code entrant.
Vous pouvez passer ausinon + AVA versionsi c'est ce que vous souhaitez utiliserce lien
Passer auMiddleware et en-têtes request.getsection utilisantce lien.
Pour tester minutieusem*nt ce gestionnaire Express, il faut quelques tests supplémentaires mais fondamentalement les mêmes principes que dans levérifierAuth
etSe déconnecter
gestionnaires.
Les tests ressemblent à ce qui suit (dans express-handlers.jest-test.js) :
décrire('se connecter', () => { test('devrait 400 si le nom d'utilisateur est absent du corps', asynchrone () => { const demande = mockRequest( {}, { mot de passe: 'chef' } ); const rés = réponse simulée(); attendre se connecter(demande, rés); attendre(rés.statut).toHaveBeenCalledWith(400); attendre(rés.json).toHaveBeenCalledWith({ message: 'le nom d'utilisateur et le mot de passe sont requis' }); }); test('devrait 400 si le mot de passe est absent du corps', asynchrone () => { const demande = mockRequest( {}, { nom d'utilisateur: 'hugo' } ); const rés = réponse simulée(); attendre se connecter(demande, rés); attendre(rés.statut).toHaveBeenCalledWith(400); attendre(rés.json).toHaveBeenCalledWith({ message: 'le nom d'utilisateur et le mot de passe sont requis' }); }); test('devrait 401 avec un message si l'utilisateur avec le nom d'utilisateur transmis n'existe pas', asynchrone () => { const demande = mockRequest( {}, { nom d'utilisateur: 'Hugo Boss', mot de passe: 'chef' } ); const rés = réponse simulée(); attendre se connecter(demande, rés); attendre(rés.statut).toHaveBeenCalledWith(401); attendre(rés.json).toHaveBeenCalledWith({ message: "Aucun utilisateur avec le nom d'utilisateur correspondant" }); }); test('devrait 401 avec un message si le mot de passe transmis ne correspond pas au mot de passe stocké', asynchrone () => { const demande = mockRequest( {}, { nom d'utilisateur: 'invité', mot de passe: 'pas-bon-mot de passe' } ); const rés = réponse simulée(); attendre se connecter(demande, rés); attendre(rés.statut).toHaveBeenCalledWith(401); attendre(rés.json).toHaveBeenCalledWith({ message: 'Mauvais mot de passe' }); }); test('devrait 201 et définir session.data avec le nom d'utilisateur si l'utilisateur existe et le bon mot de passe fourni', asynchrone () => { const demande = mockRequest( {}, { nom d'utilisateur: 'invité', mot de passe: 'patron invité' } ); const rés = réponse simulée(); attendre se connecter(demande, rés); attendre(rés.statut).toHaveBeenCalledWith(201); attendre(rés.json).avoir été appelé(); attendre(demande.session.données).égaler({ nom d'utilisateur: 'invité', }); });});
Voir un instantané du code sur GitHubgithub.com/HugoDF/mock-express-request-response/releases/tag/login-tests(cliquez sur le commit sha pour le diff pour ce changement de version).
Tests du gestionnaire de connexion en utilisant AVA + sinon
Note:Il y a (un autre) grand mur de code entrant.
Vous pouvez retourner auIl existe une versionsi c'est ce que vous souhaitez utiliserce lien
Passer auMiddleware et en-têtes request.getsection utilisantce lien.
Encore une fois, il n'y a rien de fondamentalement nouveau dans ces tests, ils sont juste plus denses et plus proches de ce que vous feriez dans une application réelle, ils sont les suivants (dans express-handlers.sinon-test.js) :
Voir un instantané du code sur GitHubgithub.com/HugoDF/mock-express-request-response/releases/tag/login-tests(cliquez sur le commit sha pour le diff pour ce changement de version).
test('login > devrait 400 si le nom d'utilisateur est absent du corps', asynchrone (t) => { const demande = mockRequest( {}, { mot de passe: 'chef' } ); const rés = réponse simulée(); attendre se connecter(demande, rés); t.vrai(rés.statut.appeléAvec(400)); t.vrai(rés.json.appeléAvec({ message: 'le nom d'utilisateur et le mot de passe sont requis' }));});test('devrait 400 si le mot de passe est absent du corps', asynchrone (t) => { const demande = mockRequest( {}, { nom d'utilisateur: 'hugo' } ); const rés = réponse simulée(); attendre se connecter(demande, rés); t.vrai(rés.statut.appeléAvec(400)); t.vrai(rés.json.appeléAvec({ message: 'le nom d'utilisateur et le mot de passe sont requis' }));});test('devrait 401 avec un message si l'utilisateur avec le nom d'utilisateur transmis n'existe pas', asynchrone (t) => { const demande = mockRequest( {}, { nom d'utilisateur: 'Hugo Boss', mot de passe: 'chef' } ); const rés = réponse simulée(); attendre se connecter(demande, rés); t.vrai(rés.statut.appeléAvec(401)); t.vrai(rés.json.appeléAvec({ message: "Aucun utilisateur avec le nom d'utilisateur correspondant" }));});test('devrait 401 avec un message si le mot de passe transmis ne correspond pas au mot de passe stocké', asynchrone (t) => { const demande = mockRequest( {}, { nom d'utilisateur: 'invité', mot de passe: 'pas-bon-mot de passe' } ); const rés = réponse simulée(); attendre se connecter(demande, rés); t.vrai(rés.statut.appeléAvec(401)); t.vrai(rés.json.appeléAvec({ message: 'Mauvais mot de passe' }));});test('devrait 201 et définir session.data avec le nom d'utilisateur si l'utilisateur existe et le bon mot de passe fourni', asynchrone (t) => { const demande = mockRequest( {}, { nom d'utilisateur: 'invité', mot de passe: 'patron invité' } ); const rés = réponse simulée(); attendre se connecter(demande, rés); t.vrai(rés.statut.appeléAvec(201)); t.vrai(rés.json.appelé); t.profondÉgal( demande.session.données, { nom d'utilisateur: 'invité' } );});
Voir un instantané du code sur GitHubgithub.com/HugoDF/mock-express-request-response/releases/tag/login-tests(cliquez sur le commit sha pour le diff pour ce changement de version).
Tester un middleware et se moquer des en-têtes Express request.get
Un autre scénario dans lequel vous souhaiterez peut-être simuler/stub les objets de requête et de réponse Express est celui du test d'une fonction middleware.
Le test du middleware est subtilement différent. De nombreux middlewares ont des conditions dans lesquelles ils ne font rien (ils appellent simplementsuivant()
). Un middleware Express doit toujours appelersuivant()
(son 3ème paramètre) ou envoyer une réponse.
Voici un exemple de middleware qui permet l'authentification à l'aide d'une clé API dans unAutorisation
en-tête du formatPorteur {API_KEY}
.
Au-delà des différences entre middleware et gestionnaire,en-têteAuth
utilise égalementreq.get()
, qui est utilisé pour obtenir les en-têtes de la requête Express.
j'ai omisapiKeyToUser
etisApiKey
.apiKeyToUser
est juste une recherche d'apiKeys vers les noms d'utilisateur. Dans une application réelle, il s'agirait d'une recherche dans une base de données, un peu comme ce qui remplaceraitobtenirUtilisateur
dans lese connecter
code.
fonction en-têteAuth(demande, rés, suivant) { si (demande.session.données) { retour suivant() } const authentificationEn-tête = demande.obtenir('autorisation') si(!authentificationEn-tête) { retour suivant() } const clé API = authentificationEn-tête .remplacer('Porteur', '') .garniture(); si (!isApiKey(clé API)) { retour suivant() } demande.session.données = { nom d'utilisateur: apiKeyToUser[clé API] } ; suivant();}
Voir un instantané du code sur GitHubgithub.com/HugoDF/mock-express-request-response/releases/tag/middleware-header-tests(cliquez sur le commit sha pour le diff pour ce changement de version).
Mise à jour de mockRequest pour prendre en charge l'accès aux en-têtes
Voici une version différente de mockRequest, c'est toujours un simple objet JavaScript, et il se moquereq.get
juste assez pour réussir les tests :
const mockRequest = (en-tête d'authentification, données de session) => ({ obtenir(nom) { si (nom === 'autorisation') retour en-tête d'authentification retour nul }, session: { données: données de session }});
Tester un middleware qui accède aux en-têtes avec Jest
La plupart des tests vérifient que rien ne change sur la session pendant l'exécution du middleware car il présente de nombreuses conditions de court-circuit.
Notez comment nous transmettons une fonction sans opération() => {}
comme 3ème paramètre (qui estsuivant
).
décrire('en-têteAuthMiddleware', () => { test('doit définir req.session.data si la clé API est en autorisation et est valide', asynchrone () => { const demande = mockRequest('76b1e728-1c14-43f9-aa06-6de5cbc064c2'); const rés = réponse simulée(); attendre headerAuthMiddleware(demande, rés, () => {}); attendre(demande.session.données).égaler({ nom d'utilisateur: 'hugo' }); }); test('ne devrait rien faire si req.session.data est déjà défini', asynchrone () => { const demande = mockRequest('76b1e728-1c14-43f9-aa06-6de5cbc064c2', { nom d'utilisateur: 'invité' }); const rés = réponse simulée(); attendre headerAuthMiddleware(demande, rés, () => {}); attendre(demande.session.données).égaler({ nom d'utilisateur: 'invité' }); }); test('ne devrait rien faire si l'en-tête d'autorisation n'est pas présent', asynchrone () => { const demande = mockRequest(indéfini); const rés = réponse simulée(); attendre headerAuthMiddleware(demande, rés, () => {}); attendre(demande.session.données).être indéfini(); }); test('ne devrait rien faire si la clé API n'est pas valide', asynchrone () => { const demande = mockRequest('clé API invalide'); const rés = réponse simulée(); attendre headerAuthMiddleware(demande, rés, () => {}); attendre(demande.session.données).être indéfini(); });});
Voir un instantané du code sur GitHubgithub.com/HugoDF/mock-express-request-response/releases/tag/middleware-header-tests(cliquez sur le commit sha pour le diff pour ce changement de version).
Tester un middleware qui accède aux en-têtes en utilisant AVA + sinon
La plupart des tests vérifient que rien ne change sur la session pendant l'exécution du middleware car il présente de nombreuses conditions de court-circuit.
Notez comment nous transmettons une fonction sans opération() => {}
comme 3ème paramètre (qui estsuivant
).
test('doit définir req.session.data si la clé API est en autorisation et est valide', asynchrone (t) => { const demande = mockRequest('76b1e728-1c14-43f9-aa06-6de5cbc064c2'); const rés = réponse simulée(); attendre headerAuthMiddleware(demande, rés, () => {}); t.profondÉgal( demande.session.données, { nom d'utilisateur: 'hugo' } );});test('ne devrait rien faire si req.session.data est déjà défini', asynchrone (t) => { const demande = mockRequest('76b1e728-1c14-43f9-aa06-6de5cbc064c2', { nom d'utilisateur: 'invité' }); const rés = réponse simulée(); attendre headerAuthMiddleware(demande, rés, () => {}); t.profondÉgal( demande.session.données, { nom d'utilisateur: 'invité' } );});test('ne devrait rien faire si l'en-tête d'autorisation n'est pas présent', asynchrone (t) => { const demande = mockRequest(indéfini); const rés = réponse simulée(); attendre headerAuthMiddleware(demande, rés, () => {}); t.est(demande.session.données, indéfini);});test('ne devrait rien faire si la clé API n'est pas valide', asynchrone (t) => { const demande = mockRequest('clé API invalide'); const rés = réponse simulée(); attendre headerAuthMiddleware(demande, rés, () => {}); t.est(demande.session.données, indéfini);});
Voir un instantané du code sur GitHubgithub.com/HugoDF/mock-express-request-response/releases/tag/middleware-header-tests(cliquez sur le commit sha pour le diff pour ce changement de version).
Clés pour tester les gestionnaires et middleware Express
Il existe quelques clés pour tester efficacement Express de la manière décrite dans cet article.
Tout d’abord, il faut comprendre ce que fait le code. C'est plus difficile qu'il n'y paraît. Tester en JavaScript consiste en grande partie à comprendre JavaScript, un peu à tester les outils et un peu à comprendre les outils utilisés dans l'application testée. Afin de se moquer des valeurs de retour de l’outil avec le bon type de données.
Tous les tests du post se résument à comprendre ce quedemande
,rés
etsuivant
sont (un objet, un objet et une fonction). Quelles propriétés ils ont/peuvent avoir, comment ces propriétés sont utilisées et s'il s'agit d'une fonction ou d'un objet.
Il ne s’agit que d’une seule approche pour tester les gestionnaires et middleware Express. L'alternative consiste à lancer le serveur Express (idéalement en mémoire à l'aide de SuperTest). J'explique plus en détail comment y parvenir"Tester une application Express avec SuperTest, Moxios et Jest"
Obtenez le manuel Jest (100 pages)
Faites passer vos tests JavaScript au niveau supérieur en apprenant les tenants et les aboutissants de Jest, la meilleure bibliothèque de tests JavaScript.
ouRejoignez des milliers de développeurs qui découvrent Node.js et JavaScript de niveau entreprise