[英]How to properly test an Express controller method with Mocha, Chai, and Sinon
I'm pretty new to using Sinon. 我对使用Sinon非常陌生。 I have the following test I've written, and it fails because res.status
always comes back as not called. 我已经编写了以下测试,但测试失败,因为res.status
总是以未调用的形式返回。
import chai from 'chai';
import 'chai/register-should';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import { db } from '../../models';
import * as loginController from '../../controllers/login';
chai.use(sinonChai);
describe('Login controller', () => {
describe('post function', () => {
let findOne, req, status, send, res;
beforeEach(() => {
findOne = sinon.stub(db.User, 'findOne');
findOne.resolves(null);
req = { body: { email: 'test@test.com', password: 'testpassword' }};
status = sinon.stub();
send = sinon.spy();
res = { send: send, status: status };
status.returns(res);
loginController.post(req, res);
});
afterEach(() => {
findOne.restore();
});
it('should return a 401 status for an invalid email', (done) => {
res.status.should.be.calledWith(401);
findOne.restore();
done();
});
});
});
The method in the controller right now is pretty simple. 现在控制器中的方法非常简单。 It uses a sequelize findOne
method first. 它首先使用一个sequelize findOne
方法。 If it doesn't find a matching email it should throw a 401. Here's what that looks like: 如果找不到匹配的电子邮件,则会抛出401。这是这样的:
export function post(req,res) {
const email = req.body.email;
const password = req.body.password;
db.User.findOne({
where: {email: email}
}).then(user => {
if (user) {
// Other stuff happens here
} else {
res.status(401).send('That email address does not exist in our system.');
}
}).catch((error) => {
res.status(500).send(error.message);
});
}
When I run the test it does get to the else statement where it should be returning the status, but the test fails and when I check the log it says that the res.status
wasn't ever called. 当我运行测试时,它确实到达了应返回状态的else语句,但是测试失败,并且当我检查日志时,它说从未调用过res.status
。
The problem here is that the spec is synchronous and doesn't take a promise into account. 这里的问题是规范是同步的,没有考虑到承诺。
It makes sense to return a promise for testability reasons: 出于可测试性的原因,返回承诺是有意义的:
export function post(req,res) {
...
return db.User.findOne(...)
...
}
This can be naturally done if route handler is async
function. 如果路由处理程序是async
函数,则可以自然完成此操作。
Since Mocha supports promises, the specs can use async
functions instead of done
callback as well: 由于Mocha支持Promise,因此规范可以使用async
函数代替done
回调:
it('should return a 401 status for an invalid email', async () => {
const handlerResult = loginController.post(req, res);
expect(handlerResult).to.be.a('promise');
await handlerResult;
res.status.should.be.calledWith(401);
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.