【问题标题】:How to trigger Express error middleware?如何触发 Express 错误中间件?
【发布时间】:2018-01-28 18:33:29
【问题描述】:

我正在尝试在 Mocha 中对这段代码进行单元测试:

app.use(function (err, req, res, next) {
    console.error(err.stack)
    res.status(500).send('Something broke!')
})

我不知道如何在 Mocha 单元测试中获取我的请求以触发它。

【问题讨论】:

    标签: node.js unit-testing express mocha.js supertest


    【解决方案1】:

    在您的路由中,您可以在next 参数中传递一个错误对象。例如:

    app.get('/some-route', (req, res, next) => {
        const error = {....};
    
        next(error);
    });
    

    或者只是抛出一个错误:

    app.get('/some-route', (req, res, next) => {
        const error = {....};
    
        throw new Error(error);
    });
    

    【讨论】:

    • 理想情况下,您不会故意在路由中抛出错误,并且可能无法(或推荐?)在测试期间很好地添加临时路由。你知道是否可以使用 supertest 来强制已经定义的路由抛出错误?
    【解决方案2】:

    首先,我会将中间件分解为它自己的文件/函数。就目前而言,它与 Express 应用程序“集成”。因此,您不仅在测试错误中间件,而且在一定程度上还测试了 Express 应用实例。

    话虽如此,将错误中间件与 Express 应用解耦:

    src/middleware/error-handler.js

    module.exports = (err, req, res, next) => {
      console.error(err.stack)
      res.status(500).send('Something broke!')
    }
    

    您仍将在主 app.js 或您设置 Express 的任何地方 .use() 它:

    const express = require('express')
    const errorHandler = require('./src/middleware/error-handler')
    const app = express()
    
    app.use(errorHandler)
    

    但是现在我们摆脱了 Express 依赖,并且有了一个可以隔离和测试的简单函数。下面是使用 Jest 进行的简单测试,您可以轻松调整它以使用 Mocha。

    __tests__/middleware/error-handler.test.js

    const errorHandler = require('../../src/middleware')
    
    describe('middleware.ErrorHandler', () => {
      /**
       * Mocked Express Request object.
       */
      let req
    
      /**
       * Mocked Express Response object.
       */
      let res
    
      /**
       * Mocked Express Next function.
       */
      const next = jest.fn()
    
      /**
       * Reset the `req` and `res` object before each test is ran.
       */
      beforeEach(() => {
        req = {
          params: {},
          body: {}
        }
    
        res = {
          data: null,
          code: null,
          status (status) {
            this.code = status
            return this
          },
          send (payload) {
            this.data = payload
          }
        }
    
        next.mockClear()
      })
    
      test('should handle error', () => {
        errorHandler(new Error(), req, res, next)
    
        expect(res.code).toBeDefined()
        expect(res.code).toBe(500)
    
        expect(res.data).toBeDefined()
        expect(res.data).toBe('Something broke!')
      })
    })
    

    【讨论】:

    • TDD 绝对有利于制动模块。为了保持单元测试的快速和集中,这是首选。但是,supertest 非常适合进行一些集成测试,例如您要确保错误正确传播到所有错误处理程序并被记录。有没有办法用 express 和 supertest 来处理这个问题?像request(app).get('/some-route').throws(new Error) 这样强制从该路由抛出错误的API 会很好。这有点令人费解,因为您的应用可能永远不会真正抛出这样的错误,但至少它会测试您的错误处理程序。
    猜你喜欢
    • 1970-01-01
    • 2019-08-24
    • 2012-02-22
    • 2016-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-27
    • 1970-01-01
    相关资源
    最近更新 更多