假设我在一个名为UserController的类中有一个函数,它在这些行中执行某些操作(其中userService.createUser()
返回一个promise):
function createUser(req, res)
{
const userInfo = req.body;
userService.createUser(userInfo)
.then(function(){res.json({message: "User added successfully"})})
.fail(function(error){res.send(error)})
.done();
}
如何测试,当promise解析时,res.json()
被调用,当promise拒绝时,res.send(error)
被调用?
我尝试过写这样的测试:
const userService = ...
const userController = new UserController(userService);
const response = {send: sinon.stub()};
...
const anError = new Error();
userService.createUser = sinon.stub().returns(Q.reject(anError));
userController.createUser(request, response);
expect(response.send).to.be.calledWith(anError);
但测试失败了" response.send从未被调用过#34;。我还尝试在调用res.send(error)
之前记录一些内容,并且记录确实发生了。
我的猜测是expect()
在执行res.send(error)
之前被调用,因为它是异步的。
我对承诺和单元测试相当新,是我的架构还是我对承诺的使用?
我使用Q代表承诺,使用mocha,chai,sinon进行单元测试。
答案 0 :(得分:2)
当您进行异步调用时,expect
行后面会调用userController.createUser()
语句。因此,当评估断言时,它尚未被调用。
要异步测试代码,您需要在done
语句中声明it
,然后手动调用以获得结果。
在您的测试文件中:
it('should work', function(done) {
...
userController.createUser(request, response);
process.nextTick(function(){
expect(response.send).to.be.calledWith(anError);
done();
});
});
这将使Mocha(我假设您正在使用它)在excpect
被调用时评估您的done()
。
或者,您可以在UserController.createUser
函数上设置cb函数,并在.done()
上调用它:
<强> UserController中强>
function createUser(req, res, cb) {
const userInfo = req.body;
userService.createUser(userInfo)
.then(function(){res.json({message: "User added successfully"})})
.fail(function(error){res.send(error)})
.done(function(){ if(cb) cb() });
}
然后进行测试:
userController.createUser(request, response, function() {
expect(response.send).to.be.calledWith(anError);
done();
});
答案 1 :(得分:1)
假设你使用Mocha或Jasmine作为框架,更简单的方法是在你刚开始时继续,但是完全跳过Sinon(因为这里不需要,除非你测试收到的实际参数):
// observe the `done` callback - calling it signals success
it('should call send on successful service calls', (done) => {
// assuming same code as in question
...
const response = {send: done};
userController.createUser(request, response);
});
// observe the `done` callback - calling it signals success
it('should call send on failing service calls', (done) => {
// assuming same code as in question
...
const response = {send: err => err? done(): done(new Error("No error received"))};
userController.createUser(request, response);
});
披露:我是Sinon维护团队的一员。