使用异步函数模拟请求错误

Simulating request error with async function

在我的 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) 函数),我该如何模拟示例中的错误?

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

并且在您的 mocha 中,您将发送一个无效的产品主体,它会捕获您的 next

执行此操作的两种最简单的方法如下:

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