如何用玩笑模拟多个调用链函数

分享于2022年07月17日 jestjs mongoose node.js 问答
【问题标题】:如何用玩笑模拟多个调用链函数(How to mock multiple call chained function with jest)
【发布时间】:2022-01-26 22:57:17
【问题描述】:

当我为我的项目编写单元测试时, 我遇到了需要在 mongoose 模块中模拟一个函数链式多次调用的情况。

如果它只调用 .populate() 一次,如下面的代码:

await mongoose.model("routeDetail").find({
            _id: {
                $in: requestBody.routeIds,
            },
        })
            .populate("organizationId")

我可以轻松地模拟它,例如 模拟 /mongoose.js

module.exports = {
    model: jest.fn().mockReturnThis(),
    find: jest.fn().mockReturnThis(),
    populate: jest.fn().mockReturnThis(),
    sort: jest.fn().mockReturnThis(),
};

测试 /myFile.test.js

mongoose.populate = jest.fn().mockReturnValueOnce(myValue);

但是... 在另一种情况下 .populate() 被多次调用,例如下面的代码,我不知道如何模拟它。

await mongoose.model("routeDetail").find({
            _id: {
                $in: requestBody.routeIds,
            },
        })
            .populate("organizationId")
            .populate("deliverDetail.orderInfo")

有人知道吗? 请帮我解决这个问题,谢谢!

  • 不要嘲笑你不拥有的东西。 Mongoose 有一个复杂的 API,将其抽象为您 确实 拥有的接口并模拟 that 以进行单元测试。使用集成测试来验证实际查询。
  • 我知道,但我目前不想重构代码,因为资源人力等许多原因,所以我可以继续这样做

【解决方案1】:

对于该特定示例,您可以模拟实现:

const model = {
  find: jest.fn(() => ({
    populate: jest.fn(() => ({
      populate: jest.fn(() => Promise.resolve([])),
    })),
  })),
};

Model 是一个对象,它有一个 find 函数,该函数返回一个带有 populate 函数的对象,该函数返回一个带有 populate 函数的对象,该函数返回一个解析空数组的 Promise

  • 那么当第二个调用是 model.find().populate() 也在同一个函数中时,我该如何模拟它?
  • 您只需覆盖每个测试,模拟的实现。在一项测试中,您将执行查找 -> 填充 -> 填充,而在另​​一项测试中:查找 -> 填充。有意义吗?
  • 但是在一个函数中调用了 2 个 mongosse,我可以拆分为 2 个案例测试。
  • 我建议您将这些调用封装在服务上。所以第一个 mongoose 调用将是第一个服务的结果(类似于 simpleFind()),第二个 mongoose 调用将是第二个服务的结果。 (类似于populatedFind())。通过这种方式,你将模拟不同的封装代码片段,并且测试起来会容易得多。