如何通过调用 next(error) 来测试 express 中间件抛出错误
How to test that express middleware throws an error by calling next(error)
我试图通过存根 next() 来捕获错误,但它失败了。
函数如下
async getUser (req, res, next) {
try {
if (!req.user) {
throw new CustomError('找不到使用者', 404)
} else {
// do something
}
} catch (err) {
next(err)
}
}
和单元测试部分
it('no user data => Error 404', async () => {
const res = mockedResponse()
const next = sinon.stub()
await getUser({}, res, next)
expect(next.getCall(0).args[0]).to.deep.equal(new CustomError('cannnot find user', 404))
})
然而测试结果表明
AssertionError: expected [Error: cannnot find user] to deeply equal [Error: cannnot find user]
是否有更好的方法来捕获函数抛出的 CustomError?
deep-eql 算法不会对错误进行深度相等。参见 https://github.com/chaijs/chai/issues/1065#issuecomment-337857345
解决方法如下:
index.js
:
const CustomError = require('./customError');
const controller = {
async getUser(req, res, next) {
try {
if (!req.user) {
throw new CustomError('找不到使用者', 404);
} else {
// do something
}
} catch (err) {
next(err);
}
},
};
module.exports = controller;
customError.js
:
class CustomError extends Error {
constructor(message, code) {
super(message);
this.code = code;
}
}
module.exports = CustomError;
index.test.js
:
const controller = require('./');
const CustomError = require('./customError');
const sinon = require('sinon');
const { expect } = require('chai');
describe('61879445', () => {
it('should throw error if user not found', async () => {
const mNext = sinon.stub();
const mReq = {};
const mRes = {};
await controller.getUser(mReq, mRes, mNext);
// chai way
expect(mNext.getCall(0).args[0]).to.be.an.instanceof(CustomError);
expect(mNext.getCall(0).args[0]).to.have.property('message', '找不到使用者');
expect(mNext.getCall(0).args[0]).to.have.property('code', 404);
// sinon way
sinon.assert.calledWith(
mNext,
sinon.match
.instanceOf(CustomError)
.and(sinon.match.has('message', '找不到使用者'))
.and(sinon.match.has('code', 404)),
);
});
});
带有覆盖率报告的单元测试结果:
61879445
✓ should throw error if user not found
1 passing (15ms)
----------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------------|---------|----------|---------|---------|-------------------
All files | 100 | 50 | 100 | 100 |
customError.js | 100 | 100 | 100 | 100 |
index.js | 100 | 50 | 100 | 100 | 6
----------------|---------|----------|---------|---------|-------------------
我试图通过存根 next() 来捕获错误,但它失败了。
函数如下
async getUser (req, res, next) {
try {
if (!req.user) {
throw new CustomError('找不到使用者', 404)
} else {
// do something
}
} catch (err) {
next(err)
}
}
和单元测试部分
it('no user data => Error 404', async () => {
const res = mockedResponse()
const next = sinon.stub()
await getUser({}, res, next)
expect(next.getCall(0).args[0]).to.deep.equal(new CustomError('cannnot find user', 404))
})
然而测试结果表明
AssertionError: expected [Error: cannnot find user] to deeply equal [Error: cannnot find user]
是否有更好的方法来捕获函数抛出的 CustomError?
deep-eql 算法不会对错误进行深度相等。参见 https://github.com/chaijs/chai/issues/1065#issuecomment-337857345
解决方法如下:
index.js
:
const CustomError = require('./customError');
const controller = {
async getUser(req, res, next) {
try {
if (!req.user) {
throw new CustomError('找不到使用者', 404);
} else {
// do something
}
} catch (err) {
next(err);
}
},
};
module.exports = controller;
customError.js
:
class CustomError extends Error {
constructor(message, code) {
super(message);
this.code = code;
}
}
module.exports = CustomError;
index.test.js
:
const controller = require('./');
const CustomError = require('./customError');
const sinon = require('sinon');
const { expect } = require('chai');
describe('61879445', () => {
it('should throw error if user not found', async () => {
const mNext = sinon.stub();
const mReq = {};
const mRes = {};
await controller.getUser(mReq, mRes, mNext);
// chai way
expect(mNext.getCall(0).args[0]).to.be.an.instanceof(CustomError);
expect(mNext.getCall(0).args[0]).to.have.property('message', '找不到使用者');
expect(mNext.getCall(0).args[0]).to.have.property('code', 404);
// sinon way
sinon.assert.calledWith(
mNext,
sinon.match
.instanceOf(CustomError)
.and(sinon.match.has('message', '找不到使用者'))
.and(sinon.match.has('code', 404)),
);
});
});
带有覆盖率报告的单元测试结果:
61879445
✓ should throw error if user not found
1 passing (15ms)
----------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------------|---------|----------|---------|---------|-------------------
All files | 100 | 50 | 100 | 100 |
customError.js | 100 | 100 | 100 | 100 |
index.js | 100 | 50 | 100 | 100 | 6
----------------|---------|----------|---------|---------|-------------------