如何正确测试 return Mongoose 查询为 Promises 的函数

How to properly test functions that return Mongoose queries as Promises

我正在尝试编写一个基本单元测试来处理下面的函数,但无法让它运行。我如何测试是否返回了正确的 npm-express 响应之类的东西?

我已经看过 , https://codeutopia.net/blog/2016/06/10/mongoose-models-and-unit-tests-the-definitive-guide/, and Unit Test with Mongoose,但还是想不通。我目前的最佳猜测和由此产生的错误低于要测试的功能。如果可能的话,除了 Mocha、Sinon 和 Chai.expect(即不是 sinon-mongoose、chai-as-expected 等),我不想使用任何东西。欢迎任何其他建议,比如我 can/should 在这里测试的其他建议。谢谢!

待测函数:

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));
}

我目前的最佳猜测单元测试:

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);
  });
});

测试留言:

  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)

这是一个有点棘手的场景。这里的问题是测试中的 findOne 存根 return 是模型对象 - 相反,它需要 return 一个包含 属性 exec 的对象,而后者又是最终解析为模型值的 promise-returning 函数...是的,如前所述,它有点棘手 :)

像这样:

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

Profile.findOne.returns(findOneResult);

您还需要在响应对象上具有 status 函数 return 包含 send 函数的对象

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

我认为您不需要更改测试中的任何其他内容,它可能会像那样工作。请注意,您使用 sinon 2.0 或更新版本才能在存根上存在 resolves 函数(或者您可以将 sinon-as-promised 与 sinon 1.x)

一起使用

这篇 post 更详细地介绍了如何处理这样的复杂对象: https://codeutopia.net/blog/2016/05/23/sinon-js-quick-tip-how-to-stubmock-complex-objects-such-as-dom-objects/