2017-08-03 3 views
1

J'essaye d'écrire un test unitaire de base pour travailler sur la fonction ci-dessous, mais je n'arrive pas à la faire fonctionner. Comment puis-je tester que quelque chose comme une réponse npm-express est renvoyé? J'ai déjà regardé Using Sinon to stub chained Mongoose calls, https://codeutopia.net/blog/2016/06/10/mongoose-models-and-unit-tests-the-definitive-guide/, et Unit Test with Mongoose, mais ne peux toujours pas le comprendre. Ma meilleure estimation actuelle, et l'erreur qui en résulte, est en dessous de la fonction à tester. Si possible, je ne veux pas utiliser autre chose que Mocha, Sinon, et Chai.expect (c'est-à-dire pas sinon-mongoose, chai-comme-prévu, etc.). Tout autre conseil, comme quoi d'autre que je peux/devrait tester ici, est le bienvenu. Je vous remercie!Comment tester correctement les fonctions qui renvoient des requêtes Mongoose en tant que promesses

La fonction à tester:

function testGetOneProfile(user_id, res) { 
    Profiles 
    .findOne(user_id) 
    .exec() 
    .then((profile) => { 
     let name = profile.user_name, 
     skills = profile.skills.join('\n'), 
     data = { 'name': name, 'skills': skills }; 
     return res 
     .status(200) 
     .send(data); 
    }) 
    .catch((err) => console.log('Error:', err)); 
} 

Mon unité la plus estimation actuelle test:

const mongoose = require('mongoose'), 
     sinon = require('sinon'), 
     chai  = require('chai'), 
     expect = chai.expect, 
     Profile = require('../models/profileModel'), 
     foo  = require('../bin/foo'); 

mongoose.Promise = global.Promise; 

describe('testGetOneProfile', function() { 
    beforeEach(function() { 
    sinon.stub(Profile, 'findOne'); 
    }); 
    afterEach(function() { 
    Profile.findOne.restore(); 
    }); 

    it('should send a response', function() { 
    let mock_user_id = 'U5YEHNYBS'; 
    let expectedModel = { 
     user_id: 'U5YEHNYBS', 
     user_name: 'gus', 
     skills: [ 'JavaScript', 'Node.js', 'Java', 'Fitness', 'Riding', 'backend'] 
    }; 
    let expectedResponse = { 
     'name': 'gus', 
     'skills': 'JavaScript, Node.js, Java, Fitness, Riding, backend' 
    }; 
    let res = { 
     send: sinon.stub(), 
     status: sinon.stub() 
    }; 
    sinon.stub(mongoose.Query.prototype, 'exec').yields(null, expectedResponse); 
    Profile.findOne.returns(expectedModel); 

    foo.testGetOneProfile(mock_user_id, res); 

    sinon.assert.calledWith(res.send, expectedResponse); 
    }); 
}); 

Le message de test:

1) testGetOneProfile should send a response: 
    TypeError: Profiles.findOne(...).exec is not a function 
     at Object.testGetOneProfile (bin\foo.js:187:10) 
     at Context.<anonymous> (test\foo.test.js:99:12) 
+0

Vous devez vérifier si vous avez la fonction 'findOne' définie dans votre module' Profile'. Vous l'avez probablement défini comme 'findone 'par exemple. – Mekicha

+0

De la documentation: 'var stub = sinon.stub (objet," méthode ");' Remplace 'object.method' par une fonction stub. Une exception est levée si la propriété n'est pas déjà une fonction. – Mekicha

+0

@Mekicha La fonction 'findOne' est définie sur' mongoose', elle devrait donc être déléguée par mon module 'Profile'. Le problème (je pense!) Est avec la structure de la promesse. L'erreur est levée sur 'exec()', pas sur 'findOne'. D'autres idées? –

Répondre

2

Ceci est un peu délicat scénario. Le problème ici est que le stub findOne dans votre test renvoie l'objet modèle - à la place, il doit renvoyer un objet contenant une propriété exec qui à son tour est une fonction de retour de promesse qui se résout finalement dans la valeur du modèle ... oui, comme mentionné, il est un peu difficile :)

Quelque chose comme ceci:

const findOneResult = { 
    exec: sinon.stub().resolves(expectedModel) 
} 

Profile.findOne.returns(findOneResult); 

Vous devez aussi avoir la fonction status sur l'objet de réponse renvoyer un objet contenant une fonction send

//if we set up the stub to return the res object 
//it returns the necessary func 
res.status.returns(res); 

Je pense que vous ne devriez pas avoir besoin de changer quoi que ce soit d'autre dans le test et cela pourrait fonctionner comme ça. Notez que vous sinon 2.0 ou plus récent pour que la fonction de résolution existe sur le stub (ou vous pouvez utiliser sinon-comme-promis avec sinon 1.x)

Cet article va dans un peu plus de détails sur comment vous pouvez faire face à objets complexes comme ça: https://codeutopia.net/blog/2016/05/23/sinon-js-quick-tip-how-to-stubmock-complex-objects-such-as-dom-objects/

+0

Cela a résolu le problème initial, mais maintenant je ne peux pas comprendre comment stub (ou?) L'objet Express 'res'. Je peux stub 'res.send (200)', mais pas la partie '.send (data) suivante. Une erreur est renvoyée à l'instruction 'return':' Erreur: TypeError: res.status (...). Send n'est pas une fonction'Le message que vous avez lié était informatif, mais je suis toujours bloqué! –

+0

@PeterMartinson c'est un problème similaire - la fonction 'res.status' doit renvoyer un objet contenant une fonction' send'. J'ai mis à jour la réponse pour cette –