【问题标题】:Simulating request error with async function使用异步函数模拟请求错误
【发布时间】:2018-02-18 15:04:15
【问题描述】:

在我的express 应用程序中,我声明这样的请求处理程序(此处简化):

export const CreateProduct = async (req, res, next) => {
  try {
    // ProductModel is a sequelize defined model
    const product = await ProductModel.create(req.body)
    res.send(product)
  } catch (err) {
    // I have raygun setup as the error handler for express
    // in this example, it will finally return 500
    next(err)
  }
}

然后像这样使用它:

import { CreateProduct } from './create_product'

export const ProductRouter = express.Router()
ProductRouter.post('/', CreateProduct)

但是,在运行我的测试时,nyc/istanbul 会抱怨 9 行是 Uncovered Line (在我的示例中,它是 next(err) 函数),我该如何模拟我的例子有错误吗?

【问题讨论】:

    标签: node.js async-await mocha.js istanbul supertest


    【解决方案1】:

    更简单的方法是为您的ProductModel 创建一个验证机制,当您使用无效数据创建产品时会引发一些验证错误。

    在您的 mocha 中,您将发送一个无效的产品正文,它会捕获您的 next

    【讨论】:

    • 我接受您的回答,因为它是解决我的特殊情况的最短和最简单的解决方案。谢谢大家!
    【解决方案2】:

    以下两种最简单的方法如下:

    1) 承认控制器不能进行单元测试,因为它们不能进行单元测试,它们将成为您集成测试的一部分,因为这是真的,您将尽可能多地移出可单元测试的代码在物理上尽可能地使用它们,并将它们限制在编​​写能够被测试的代码片段之外。这很好;无论如何,从单个请求的角度来看,Express 控制器有点像应用程序中的 main 方法,因此只要将 main 是'不是做繁重的工作,而是实例化和运行正在做的事情。

    2) 编写您的函数,以便它们都能接收到完成工作所需的所有道具,而且,它们几乎总是从其他文件(而不是它们定义的文件)接收它们,除非赋值只是作为默认值。

    在控制器的情况下,如果您希望控制器是可单元测试的,您可以将其预配置为接受 ProductModel 来使用(或要使用的功能),而不是假设您要拉入真实模型。

    export const CreateProduct = (ProductModel) => async (req, res, next) => {
      const productData = req.body
      try {
        const product = await ProductModel.create(productData)
        res.send(product)
      } catch (err) {
        next(err)
      }
    }
    
    
    
    import { CreateProduct } from './create_product'
    import { ConfigureProductModel } from './somewhere_else'
    
    export const ProductRouter = express.Router()
    ProductRouter.post('/', CreateProduct(ConfigureProductModel(database)))
    

    现在来测试一下,您可以轻松地创建一个CreateProduct,并在其中传入一个假的ProductModel。如果你使用 ConfigureProductModel 作为工厂的例子,你可以通过传递一个假的数据库实例来测试 it(如果你这样做了,确实有那个级别的控制)。

    就我个人而言,就像我说的,作为一个控制器,我想尽可能多地移除控制,所以我可能会删除大部分命令式代码。

    const CreateProduct = ProductModel => (req, res, next) =>
      ProductModel.create(req.body)
        .then(product => res.send(product))
        .catch(next);
    

    【讨论】:

    • 非常感谢您的解释。我选择接受 Alexandru 的回答,因为它直接回答了我的特殊情况。然而,我很高兴你花时间写这个很棒的解释。这对我重新思考如何构建我的 Express 应用程序有很大帮助。
    • @borislemke Fair,看在我的份上,我并不担心。请记住,您当前需要实时互联网和实时数据库连接,才能运行测试。许多系统中的许多人都在这样的系统中收取了信用卡费用,还有更多人在没有连接到网络的情况下无法做任何工作。这些建议不仅仅是为了更好的覆盖率、更容易的测试或更简洁的代码;这些只是一些副作用。
    猜你喜欢
    • 2021-01-30
    • 1970-01-01
    • 1970-01-01
    • 2013-03-20
    • 2019-05-13
    • 2021-08-11
    • 1970-01-01
    • 2019-01-03
    • 1970-01-01
    相关资源
    最近更新 更多