首页 文章

NodeJS:如何在使用Mocha,Chai,Sinon进行测试时验证promise内部的函数调用?

提问于
浏览
-1

我是使用Mocha,Chai和Sinon在NodeJS中进行单元测试的新手 . 我一直在尝试为API endpoints 编写一个单元测试用例,如果在Promise解决方案中从API调用 res.status(200).send(); ,我正在努力测试 . 以下是代码:

controller.js - 具有单元测试功能

const User = require("./user_model");

module.exports = {
    getUserById(req, res) {
        const { params: reqParams } = req,
            { userId } = reqParams;

        User.findOne({ _id: userId })
            .exec()
            .then(function(userFromDb) {
                res.status(200).send();    // unable to test if this is getting called.
            })
            .catch((err) => res.status(500).send());
    }
};

test.js - 是否有单元测试

const sinon = require("sinon"),
    User = require("./user_model"),
    controller = require("../controller");

require("sinon-mongoose");

describe('users', function() {
    it('getUserById', function() {
        const validReqObj = {
            params: {
                userId: "123"
            }
        };

        const mock = sinon.mock(User);
        mock.expects("findOne").withArgs({ _id: validReqObj.params.userId })
            .chain("exec")
            .resolves({ _id: validReqObj.params.userId });

        const validRes = {
            status: function(statusCode) {
                sinon.assert.match(statusCode, 200);

                return {
                    send: function() {

                    }
                };
            }
        };

        controller.getUserById(validReqObj, validRes);

        mock.restore();
        mock.verify();
    });
});

如您所见,我的测试做了两件事:

  • 模拟mongoose findOne 函数并测试 findOne 的承诺分辨率是否正常 .

  • 断言使用200状态代码调用 res.status() .

它不测试 res.status() 是否被调用 . 例如,如果我从controller.js中删除行 res.status(200).send(); ,则测试仍然通过 .

我尝试在 res.status 上创建spy . 它没有按预期工作 .

2 回答

  • 2

    问题是你的代码没有任何东西可以指示异步函数何时完成 . 虽然我们可以在测试中添加一个计时器来解决这个问题,但它有点废话解决方案 .

    以一种很好的方式解决这个问题的最简单方法是从函数中返回promise:

    return User.findOne({ _id: userId })
           ....
    

    在此之后,在您的测试中,您可以简单地执行以下操作:

    return controller.getUserById(validReqObj, validRes).then(function() {
        mock.restore();
        mock.verify();
    });
    

    注意测试中的返回 - 这允许mocha检测它是带有promise的异步测试 .

  • 0

    这是因为 getUserById 是异步函数 . 即使您为 User 模型创建了模拟, getUserById 仍然是异步的 .

    要创建正确的测试,您可以执行以下操作:

    • getUserById 函数返回promise并创建一个它测试的promise链 .

    • 使用 supertest 模块发送真实的http请求并验证响应 .

相关问题