NodeJS:如何在使用 Mocha、Chai、Sinon 进行测试时验证 promise 解析中的函数调用?
NodeJS: How to verify a function call inside promise resolution while testing using Mocha, Chai, Sinon?
我刚开始使用 Mocha、Chai 和 Sinon 在 NodeJS 中进行单元测试。我一直在尝试为 API 端点编写单元测试用例,并且正在努力测试 res.status(200).send();
是否从 Promise 解析中的 API 调用。下面是代码:
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
的 promise 解析是否正确。
- 断言
res.status()
被调用时状态代码为 200。
它甚至不测试 res.status()
是否被调用。例如,如果我从 controller.js 中删除行 res.status(200).send();
,测试仍然通过。
我尝试在 res.status
上创建 spy。它没有按预期工作。
因为getUserById
是异步函数。即使您为 User
模型创建了模拟,getUserById
仍然是异步的。
要创建适当的测试,您可以执行以下操作:
- return 来自
getUserById
函数的承诺并创建它测试的承诺链。
- 使用
supertest
模块发送真实的 http 请求并验证响应。
问题是您的代码没有指示异步函数何时完成。虽然我们可以在测试中添加一个计时器来解决这个问题,但这是一个有点废话的解决方案。
最好地解决这个问题的最简单方法是 return 您函数的承诺:
return User.findOne({ _id: userId })
....
在此之后,在你的测试中你可以简单地做这样的事情:
return controller.getUserById(validReqObj, validRes).then(function() {
mock.restore();
mock.verify();
});
还要注意测试中的 return - 这允许 mocha 检测它是一个带有承诺的异步测试。
我刚开始使用 Mocha、Chai 和 Sinon 在 NodeJS 中进行单元测试。我一直在尝试为 API 端点编写单元测试用例,并且正在努力测试 res.status(200).send();
是否从 Promise 解析中的 API 调用。下面是代码:
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
的 promise 解析是否正确。 - 断言
res.status()
被调用时状态代码为 200。
它甚至不测试 res.status()
是否被调用。例如,如果我从 controller.js 中删除行 res.status(200).send();
,测试仍然通过。
我尝试在 res.status
上创建 spy。它没有按预期工作。
因为getUserById
是异步函数。即使您为 User
模型创建了模拟,getUserById
仍然是异步的。
要创建适当的测试,您可以执行以下操作:
- return 来自
getUserById
函数的承诺并创建它测试的承诺链。 - 使用
supertest
模块发送真实的 http 请求并验证响应。
问题是您的代码没有指示异步函数何时完成。虽然我们可以在测试中添加一个计时器来解决这个问题,但这是一个有点废话的解决方案。
最好地解决这个问题的最简单方法是 return 您函数的承诺:
return User.findOne({ _id: userId })
....
在此之后,在你的测试中你可以简单地做这样的事情:
return controller.getUserById(validReqObj, validRes).then(function() {
mock.restore();
mock.verify();
});
还要注意测试中的 return - 这允许 mocha 检测它是一个带有承诺的异步测试。