【问题标题】:Unit testing validation with express-validator使用 express-validator 进行单元测试验证
【发布时间】:2015-04-30 09:48:48
【问题描述】:

如何对使用 express-validator 完成的验证进行单元测试?

我尝试创建一个虚拟请求对象,但我收到错误: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();
    });
});

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

【问题讨论】:

    标签: node.js validation unit-testing express


    【解决方案1】:

    这是新的 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 实现中间件的方式。

    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);
      }));
    };
    

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

    【讨论】:

      【解决方案2】:

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

      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']);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-05
        • 2014-02-01
        • 2012-09-14
        • 1970-01-01
        • 2020-06-29
        • 2022-08-09
        相关资源
        最近更新 更多