Unit testing 使用express validator的单元测试节点控制器/承诺
我正在使用“express validator”中间件包验证此Unit testing 使用express validator的单元测试节点控制器/承诺,unit-testing,express,promise,sinon,Unit Testing,Express,Promise,Sinon,我正在使用“express validator”中间件包验证此exampleController端点的一些参数。在单元测试中,删除此控制器的最佳方法是什么?我经常会遇到这样的错误: TypeError: errors.isEmpty is not a function 路由器 var controller = require('./controllers/exampleController.js'); var express = require('express'); var router =
exampleController
端点的一些参数。在单元测试中,删除此控制器的最佳方法是什么?我经常会遇到这样的错误:
TypeError: errors.isEmpty is not a function
路由器
var controller = require('./controllers/exampleController.js');
var express = require('express');
var router = express.Router();
router.get('/example', controller.exampleController);
exampleController.js
exports.doSomething = function(req, res, next) {
var schema = {
'email': {
in: 'query',
isEmail: {
errorMessage: 'Invalid Email'
}
},
'authorization': {
in: 'headers',
// custom test
isValidAuthToken: {
errorMessage: 'Missing or malformed Bearer token'
}
}
};
// Validate headers/query params
req.check(schema);
// Handle response
req.getValidationResult()
.then(function(errors) {
if (!errors.isEmpty()) {
return res.status(400).json({ error: 'Bad Request' });
} else {
var context = {
email: req.query.email,
};
return res.render('index', context);
}
})
};
测试
var chai = require('chai');
var sinonChai = require('sinon-chai');
chai.Should();
chai.use(sinonChai);
global.sinon = require('sinon');
var sinonStubPromise = require('sinon-stub-promise');
sinonStubPromise(sinon);
var rewire = require('rewire');
var exampleController = rewire('../controllers/exampleController.js');
var errorsResponse = [{
param: 'email',
msg: 'Invalid Email',
value: undefined
}];
describe('exampleController', function() {
var req;
var res;
beforeEach(function() {
req = {
headers: {},
query: {},
check: sinon.spy(),
getValidationResult: sinon.stub().returnsPromise()
};
res = {
status: sinon.stub().returns({
json: json
}),
render: sinon.spy()
};
});
afterEach(function() {
req.query = {};
});
context('when missing email query param', function() {
beforeEach(function() {
req.getValidationResult.resolves(errorsResponse);
exampleController.doSomething(req, res);
});
it('should call status on the response object with a 400 status code', function() {
res.status.should.be.calledWith(400);
});
it('should call json on the status object with the error', function() {
json.should.be.calledWith({ error: 'Bad Request' });
});
});
});
});
您为验证控制器而构建单元测试的方式实际上并不一致。我将尝试向您详细介绍这些问题和解决方法,但在我们继续之前,请先看一下这篇关于的精彩文章 好的,关于您显示的初始错误
TypeError:errors.isEmpty不是一个函数
,它不是由于您为stubgetValidationResult()方法设置的响应对象格式错误而导致的
从该方法打印出示例响应对象后,您将注意到正确的结构如下:
{ isEmpty: [Function: isEmpty],
array: [Function: allErrors],
mapped: [Function: mappedErrors],
useFirstErrorOnly: [Function: useFirstErrorOnly],
throw: [Function: throwError] }
而不是您的回复版本:
var errorsResponse = [{
param: 'email',
msg: 'Invalid Email',
value: undefined
}];
isEmpty()是一个顶级函数,您应该使用数组属性来存储错误列表
我附加了一个控制器和测试场景的改进版本,以便您可以将其与前面文章中介绍的最佳实践相关联
controller.js
test.js
更新版本的测试中需要注意的几点
- 与其手动构造请求/响应对象,不如使用已经存在的用于此作业的库。在我的版本中,我使用的是“”这在表达上几乎是一个标准
- 测试控制器时,与其手动调用服务方法,不如通过模拟HTTP请求对象使用自然路由机制。通过这种方式,您可以覆盖快乐和悲伤的路由路径
- 使用一个通用的HTTP req/res模拟库,意味着您的工作量会减少—您只需使用非标准函数扩展factory对象(例如getValidationResult()(来自express validator)并无缝添加间谍/存根
- 最后,该库支持在响应事件上附加事件侦听器,否则无法手动模拟这些事件。在本例中,我们正在侦听响应对象中的end事件,该响应对象在
返回res.status(400).json({error:'Bad Request')之后调用代码>方法已在控制器中调用
希望我把事情弄清楚一点:)
var express = require('express');
var router = express.Router();
router.get('/example', function(req, res) {
var schema = {
'email': {in: 'query',
isEmail: {
errorMessage: 'Invalid Email'
}
}
};
// Validate headers/query params
req.check(schema);
// Handle response
req.getValidationResult()
.then(function(errors) {
if (!errors.isEmpty()) {
return res.status(400).json({
error: 'Bad Request'
});
} else {
var context = {
email: req.query.email,
};
return res.render('index', context);
}
});
});
module.exports = router;
'use strict';
const chai = require('chai');
const sinon = require('sinon');
const SinonChai = require('sinon-chai');
var sinonStubPromise = require('sinon-stub-promise');
sinonStubPromise(sinon);
chai.use(SinonChai);
chai.should();
var mockHttp = require('node-mocks-http');
var controller = require('./controller.js');
describe.only('exampleController', function() {
context('when missing email query param', function() {
var req;
var res;
beforeEach(function() {
// mock the response object
// and attach an event emitter
// in order to be able to
// handle events
res = mockHttp.createResponse({
eventEmitter: require('events').EventEmitter
});
});
it('should call status on the response object with a 400 status code',
(done) => {
// Mocking req and res with node-mocks-http
req = mockHttp.createRequest({
method: 'GET',
url: '/example'
});
req.check = sinon.spy();
var errorsResponse = {
isEmpty: function() {
return false;
},
array: [{
param: 'email',
msg: 'Invalid Email',
value: undefined
}]
};
// stub the getValidationResult()
// method provided by the 'express-validator'
// module
req.getValidationResult = sinon.stub().resolves(errorsResponse);
// spy on the response status
sinon.spy(res, 'status');
sinon.spy(res, 'json');
// called when response
// has been completed
res.on('end', function() {
try {
// assert status and JSON args
res.status.should.have.been.calledWith(400);
res.json.should.have.been.calledWith({error: 'Bad Request'});
done();
} catch (e) {
done(e);
}
});
// Call the handler.
controller.handle(req, res);
});
});
});