Node.js - 内部模拟 promise 的函数单元测试
Node.js - unit test for function with mocked promise inside
我目前正在 JavaScript 制作一个小型服务器,作为学习过程的一部分,我正在为功能编写单元测试。不幸的是,我 运行 在处理承诺的某个测试中遇到了重大困难。下面是路由器模块,为了方便测试,有单独的handlePUT函数。
const express = require('express');
const service = require('../service/user.service');
const dutyStatusRouter = express.Router();
const output = console;
function handlePUT(req, res) {
service.updateUserStatus()
.then((fulfilled) => {
res.status(fulfilled);
res.send();
})
.catch(() => {
res.status(500);
res.send();
});
}
dutyStatusRouter.route('/').put(handlePUT);
updateUserStatus 函数基本上切换数据库中的布尔值,看起来有点像这样:
function updateUserStatus() {
return new Promise((resolve, reject) => {
if (…) {
resolve(201);
} else if (…) {
resolve(200);
} else {
reject();
}
});
}
至于单元测试,我使用 mocha/chai 和 proxyquire 来创建模拟 updateUserStatus。
const chai = require('chai');
const sinon = require('sinon');
const proxyquire = require('proxyquire');
const serviceStub = {};
describe('=== Unit test ===', () => {
it('Handle PUT test: promise kept', async () => {
const dutyStatusRouter = proxyquire('../../router/duty-status.router', {
'../service/user.service': serviceStub,
});
serviceStub.updateUserStatus = () => {
return new Promise((resolve, reject) => {
resolve(200);
});
};
const res = {
status: sinon.fake(),
send: sinon.fake(),
};
await dutyStatusRouter.handlePUT({}, res);
chai.assert(res.status.calledOnceWith(200));
});
});
每当我尝试 运行 单元测试时,我都会收到错误 Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
。如果我尝试添加 done()
它仍然会失败,并给出错误消息 Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both.
找到了有效的解决方案,所以我将其添加到此处:
const chai = require('chai');
const sinon = require('sinon');
const proxyquire = require('proxyquire');
const serviceStub = {};
const dutyStatusRouter = proxyquire('../../router/duty-status.router', {
'../service/user.service': serviceStub,
});
describe('=== Unit test ===', () => {
it('Handle PUT test: promise kept', (done) => {
serviceStub.updateUserStatus = sinon.stub().resolves(200);
const res = {
status: sinon.fake(),
send: sinon.fake(),
};
dutyStatusRouter.handlePUT({}, res).then(() => {
chai.assert(res.status.calledWith(200));
done();
});
});
});
注意:我稍微更改了 handlePUT 函数,现在看起来像这样(我只是添加了一个 return):
function handlePUT(req, res) {
return service.updateUserStatus()
.then((fulfilled) => {
output.log('Promise fulfilled');
res.status(fulfilled);
res.send();
})
.catch(() => {
output.log('Promise unfulfilled');
res.status(500);
res.send();
});
}
我目前正在 JavaScript 制作一个小型服务器,作为学习过程的一部分,我正在为功能编写单元测试。不幸的是,我 运行 在处理承诺的某个测试中遇到了重大困难。下面是路由器模块,为了方便测试,有单独的handlePUT函数。
const express = require('express');
const service = require('../service/user.service');
const dutyStatusRouter = express.Router();
const output = console;
function handlePUT(req, res) {
service.updateUserStatus()
.then((fulfilled) => {
res.status(fulfilled);
res.send();
})
.catch(() => {
res.status(500);
res.send();
});
}
dutyStatusRouter.route('/').put(handlePUT);
updateUserStatus 函数基本上切换数据库中的布尔值,看起来有点像这样:
function updateUserStatus() {
return new Promise((resolve, reject) => {
if (…) {
resolve(201);
} else if (…) {
resolve(200);
} else {
reject();
}
});
}
至于单元测试,我使用 mocha/chai 和 proxyquire 来创建模拟 updateUserStatus。
const chai = require('chai');
const sinon = require('sinon');
const proxyquire = require('proxyquire');
const serviceStub = {};
describe('=== Unit test ===', () => {
it('Handle PUT test: promise kept', async () => {
const dutyStatusRouter = proxyquire('../../router/duty-status.router', {
'../service/user.service': serviceStub,
});
serviceStub.updateUserStatus = () => {
return new Promise((resolve, reject) => {
resolve(200);
});
};
const res = {
status: sinon.fake(),
send: sinon.fake(),
};
await dutyStatusRouter.handlePUT({}, res);
chai.assert(res.status.calledOnceWith(200));
});
});
每当我尝试 运行 单元测试时,我都会收到错误 Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
。如果我尝试添加 done()
它仍然会失败,并给出错误消息 Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both.
找到了有效的解决方案,所以我将其添加到此处:
const chai = require('chai');
const sinon = require('sinon');
const proxyquire = require('proxyquire');
const serviceStub = {};
const dutyStatusRouter = proxyquire('../../router/duty-status.router', {
'../service/user.service': serviceStub,
});
describe('=== Unit test ===', () => {
it('Handle PUT test: promise kept', (done) => {
serviceStub.updateUserStatus = sinon.stub().resolves(200);
const res = {
status: sinon.fake(),
send: sinon.fake(),
};
dutyStatusRouter.handlePUT({}, res).then(() => {
chai.assert(res.status.calledWith(200));
done();
});
});
});
注意:我稍微更改了 handlePUT 函数,现在看起来像这样(我只是添加了一个 return):
function handlePUT(req, res) {
return service.updateUserStatus()
.then((fulfilled) => {
output.log('Promise fulfilled');
res.status(fulfilled);
res.send();
})
.catch(() => {
output.log('Promise unfulfilled');
res.status(500);
res.send();
});
}