使用express-validator进行单元测试验证

时间:2015-02-27 15:58:01

标签: node.js validation unit-testing express

如何对使用快速验证器完成的验证进行单元测试?

我尝试过创建虚拟请求对象,但收到错误:TypeError: Object #<Object> has no method 'checkBody'。我能够手动测试验证在应用程序中的工作情况。

以下是我的尝试:

describe('couponModel', function () {
    it('returns errors when necessary fields are empty', function(done){
        var testBody = {
            merchant : '',
            startDate : '',
            endDate : ''
        };
        var request = {
            body : testBody
        };
        var errors = Model.validateCouponForm(request);
        errors.should.not.be.empty;
        done();
    });
});

我的理解是,当我在我的快速应用程序中有checkBody时,app.use(expressValidator())方法被添加到请求对象中,但因为我只测试验证是否在此单元测试中有效没有可用的快速应用程序的实例,并且我正在测试的验证方法无论如何都不直接从它调用,因为它只通过后期路由调用,我不想调用单元测试,因为它涉及到数据库操作。

2 个答案:

答案 0 :(得分:3)

这是新的express-validator api(v4)的解决方案:

tl; dr:您可以使用功能:

exports.testExpressValidatorMiddleware = async (req, res, middlewares) => {
  await Promise.all(middlewares.map(async (middleware) => {
    await middleware(req, res, () => undefined);
  }));
};

可以像这个

一样调用它
const { validationResult } = require('express-validator/check');

await testExpressValidatorMiddleware(req, res, expressValidatorMiddlewareArray);
const result = validationResult(req);
expect(result....

这些解决方案假设您具有async / await语法。您可以使用node-mocks-http库来创建reqres对象。

说明:

express-validator数组中的每个元素作为中间件应用于路由。说这是你的阵列:

[
  check('addresses.*.street').exists(),
  check('addresses.*.postalCode').isPostalCode(),
]

每个检查都将作为中间件加载。

为了测试中间件,我们需要实现一个与表达实现中间件的方式类似的功能。

Express中间件始终接受三个参数,即请求和响应对象,以及它应调用的下一个函数(按惯例next)。我们为什么需要next?对于我们希望我们的中间件在执行功能之后之前执行某些操作的情况,例如

const loggerMiddleware = (req, res, next) => {
  console.log('req body is ' + req.body);
  next();
  console.log('res status is ' + res.status);
};

但是express-validator没有这样做,它只是在每个验证器完成后调用next()。出于这个原因,我们的实现并不需要打扰next()

相反,我们可以依次运行每个中间件并将空函数作为next传递,以避免TypeError

middlewares.map((middleware) => {
  middleware(req, res, () => undefined);
});

但是这不起作用,因为express-validator中间件会返回promise,我们需要等待它们解决...

middlewares.map(async (middleware) => {
  await middleware(req, res, () => undefined);
});

我们不想继续前进,直到迭代中的所有承诺都得到解决(Promise.all上的Mozilla文档为here):

await Promise.all(middlewares.map(async (middleware) => {
  await middleware(req, res, () => undefined);
}));

我们应该将其作为可重用的函数提取:

exports.testExpressValidatorMiddleware = async (req, res, middlewares) => {
  await Promise.all(middlewares.map(async (middleware) => {
    await middleware(req, res, () => undefined);
  }));
};

现在我们已经找到了解决方案。如果有人可以改进这个实现,我很乐意进行编辑。

答案 1 :(得分:1)

我遇到了同样的问题,我不得不用这个创建方法:

var validRequest = {
  // Default validations used
  checkBody: function () { return this; },
  checkQuery: function () { return this; },
  notEmpty: function () { return this; },

  // Custom validations used
  isArray: function () { return this; },
  gte: function () { return this; },

  // Validation errors
  validationErrors: function () { return false; }
};

function getValidInputRequest(request) {
    Object.assign(request, validRequest);
    return request;
}

因此,在您的代码中,您必须调用getValidInputRequest帮助程序:

describe('couponModel', function () {
  it('returns errors when necessary fields are empty', function(done){
      var testBody = {
          merchant : '',
          startDate : '',
          endDate : ''
      };
      var request = {
          body : testBody
      };

      request = getValidInputRequest(request); // <-- Update the request

      var errors = Model.validateCouponForm(request);
      errors.should.not.be.empty;
      done();
  });
});

现在,request对象具有body属性以及express-validator所需的所有方法。

如果你想测试验证器失败的情况,你应该使用这样的东西:

function getInvalidInputRequest(request, errorParams) {
    // Get de default valid request
    Object.assign(request, validRequest);

    // Override the validationErrors function with desired errors
    request.validationErrors = function () {
        var errors = [];
        errorParams.forEach(function(error){
            errors.push({msg: 'the parameter "'+ error +'" is mandatory'})
        });
        return errors;
    };
    return request;
}

要更新请求,您应该这样做:

request = getInvalidInputRequest(request, ['mandatory_param_1', 'mandatory_param_2']);