如何在Sinon中存根带有多个参数的猫鼬方法?

时间:2019-02-28 07:45:06

标签: node.js unit-testing mongoose sinon sinon-chai

我在Node.js中使用Mongoose,这是我的DAO方法。

function findPostsByCategoryId(categoryId, first, second) {
    var sortingOrd = { 'createdAt': -1 };
    return Post.find({ 'categoryId': categoryId }).sort(sortingOrd).skip(first).limit(second);
}

现在,我想在测试用例中使用Sinon来存储这样的方法。

describe('findPostsByCategoryId', function () {
    it('should find post by category id', function () {
        var stub = sinon.stub(Post, 'find');
        stub.callsFake(() => {
            return Promise.resolve(posts);
        });
        postDao.findPostsByCategoryId(1, 2, 3).then(response => {
            assert.length(response, 1);
        })
            .catch((error) => {
                assert.isDefined(error);
            });
    });
});

这向我返回一个错误,提示“ TypeError:Post.find(...)。sort不是函数”。

您能否阐明如何对具有多个链接功能的DAO方法进行存根处理?

2 个答案:

答案 0 :(得分:0)

要像这样简单地链接stubspy实例而链接的单元测试功能,并验证它们是否以期望的值被调用:

it('should find post by category id', function () {
  const limitSpy = sinon.spy();
  const skipStub = sinon.stub().returns({ limit: limitSpy });
  const sortStub = sinon.stub().returns({ skip: skipStub });
  const findStub = sinon.stub(Post, 'find').returns({ sort: sortStub });

  postDao.findPostsByCategoryId(1, 2, 3);

  sinon.assert.calledWithExactly(findStub, { 'categoryId': 1 });  // SUCCESS
  sinon.assert.calledWithExactly(sortStub, { 'createdAt': -1 });  // SUCCESS
  sinon.assert.calledWithExactly(skipStub, 2);  // SUCCESS
  sinon.assert.calledWithExactly(limitSpy, 3);  // SUCCESS
});

答案 1 :(得分:0)

这是单元测试解决方案:

dao.js

const Post = require("./models/post");

function findPostsByCategoryId(categoryId, first, second) {
  var sortingOrd = { createdAt: -1 };
  return Post.find({ categoryId: categoryId })
    .sort(sortingOrd)
    .skip(first)
    .limit(second);
}

module.exports = {
  findPostsByCategoryId,
};

./models/post.js

// simulate Post model
const Post = {
  find(where) {
    return this;
  },
  sort(...args) {
    return this;
  },
  skip(...args) {
    return this;
  },
  limit(n) {},
};

module.exports = Post;

dao.test.js

const dao = require("./dao");
const Post = require("./models/post");
const sinon = require("sinon");
const { expect } = require("chai");

describe("Name of the group", () => {
  afterEach(() => {
    sinon.restore();
  });
  it("should pass", () => {
    sinon.stub(Post);
    Post.find.returnsThis();
    Post.sort.returnsThis();
    Post.skip.returnsThis();
    const mResponse = { rowCount: 100 };
    Post.limit.resolves(mResponse);

    return dao.findPostsByCategoryId(1, 2, 3).then((response) => {
      expect(response).to.be.eql(mResponse);
      sinon.assert.calledWithExactly(Post.find, { categoryId: 1 });
      sinon.assert.calledWithExactly(Post.sort, { createdAt: -1 });
      sinon.assert.calledWithExactly(Post.skip, 2);
      sinon.assert.calledWithExactly(Post.limit, 3);
    });
  });
});

带有覆盖率报告的单元测试结果:

  54920719
    ✓ should pass


  1 passing (14ms)

-----------------|----------|----------|----------|----------|-------------------|
File             |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------------|----------|----------|----------|----------|-------------------|
All files        |    89.66 |      100 |    55.56 |    89.66 |                   |
 54920719        |      100 |      100 |      100 |      100 |                   |
  dao.js         |      100 |      100 |      100 |      100 |                   |
  dao.test.js    |      100 |      100 |      100 |      100 |                   |
 54920719/models |       40 |      100 |        0 |       40 |                   |
  post.js        |       40 |      100 |        0 |       40 |            4,7,10 |
-----------------|----------|----------|----------|----------|-------------------|

源代码:https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/54920719