【问题标题】:Why does jest mockResolvedValueOnce called multiple times returns the same value?为什么多次调用 jest mockResolvedValueOnce 返回相同的值?
【发布时间】:2022-02-10 06:31:56
【问题描述】:

我有一个类方法,我多次触发@google-cloud/firestore。我想通过相同的.get() 方法多次模拟调用。 多次使用 mockResolvedValueOnce 并返回不同的值,第二个值将被忽略。

    jest.doMock('@google-cloud/firestore', () => class {
      collection () {
        return {
          get: jest.fn().mockResolvedValue({
            docs: []
          }),
          doc: () => {
            return {
              set: jest.fn(),
              get: jest.fn().mockResolvedValueOnce({})
            }
          },
          limit: () => {
            return {
              get: jest.fn().mockResolvedValue({ empty: true })
            }
          },
          onSnapshot: jest.fn(),
          select: () => {
            return {
              get: jest.fn() // <------------ MULTIPLE CALLS CHAINED BELOW
                .mockResolvedValueOnce({
                  size: 1
                }).mockResolvedValueOnce({
                  size: 2
                })
            }
          }
        }
      }
    })

当我console.log(snapshot.size) 时,两次调用都会两次返回相同的值“1”。

if (isEmptyModels || isStatsEmptyModels) {
  // ...
  console.log('???? [STATS][MODELS] - Fulfilling the counters')
  await Database.collection('models').select('id').get().then(snapshot => {
    console.log(snapshot.size) // <--------- 1st call
    this.fields.models.count = snapshot.size
    this.fields.models.linked = snapshot.size
  })
  // ...
}

if (isEmptyProducts1P || isStatsEmptyProducts1P) {
  // ...
  console.log('???? [STATS][PRODUCTS1P] - Fulfilling the counters')
  await Database.collection('products1P').select('isMaintained').get().then(snapshot => {
    console.log(snapshot.size) // <--------- 2nd call
    snapshot.forEach(doc => {
      if (doc.data().isMaintained) {
        // ...
      }
    })
    // ...
  })
  // ...
}

为什么会这样,这里做错了什么?

错误信息是:

  console.log
    ???? [STATS][MODELS] - Fulfilling the counters

      at Statistics.fulfillProductsCount (app/services/statistics/index.js:95:15)

  console.log
    1

      at app/services/statistics/index.js:97:17

  console.log
    ???? [STATS][PRODUCTS1P] - Fulfilling the counters

      at Statistics.fulfillProductsCount (app/services/statistics/index.js:106:15)

  console.log
    1

      at app/services/statistics/index.js:108:17


    TypeError: snapshot.forEach is not a function

      117 |       await Database.collection('products1P').select('isMaintained').get().then(snapshot => {
      118 |         console.log(snapshot.size)
    > 119 |         snapshot.forEach(doc => {
          |                  ^
      120 |           if (doc.data().isMaintained) {
      121 |             this.fields.products1P.maintained += 1
      122 |           } else {

      at app/services/statistics/index.js:119:18

【问题讨论】:

    标签: node.js unit-testing jestjs


    【解决方案1】:

    这是因为每次调用Database.collection(),它都会创建一个新对象,而作为一个新对象,这是第一次调用它的属性。对集合内的其他函数也有效。

    我的意思是 Database.collection 是一个函数,它返回一个对象,该对象包含其他函数,这些函数返回包含模拟属性的对象。通过这种方式模拟,您将永远无法使用模拟...ValueOnce。但是,我看到了两种“绕过”这个问题的方法:

    1 - 简短但矛盾的方式

    您可以使用.mockReturnThis() 来避免进入深度模拟对象/函数,但在处理具有多次相同方法名称的“胖”类时可能会很快发生冲突。 In 在模拟可链接方法时也很有帮助(例如:使用 .find().filter().sort()... 的 ORM 查询)。

    jest.doMock('@google-cloud/firestore', () => class {
      collection = jest.fn().mockReturnThis();
      select = jest.fn().mockReturnThis();
      get = jest.fn().mockResolvedValueOnce({ size: 1 }).mockResolvedValueOnce({ size: 2 });
    })
    

    2 - 漫长而有效的方法

    模拟整个集合方法一次,而不是只模拟 collection().select().get()

    Database.collection.prototype.mockReturnValueOnce({
      select: () => {
        get: () => ({ size: 1 })
      }
    }).mockReturnValueOnce({
      select: () => {
        get: () => ({ size: 2 })
      }
    })
    

    --> 您将需要访问模拟类并模拟原型的方法“集合”(collection = jest.fn())。

    【讨论】:

    • 我尝试了第二种方法,它奏效了。谢谢你。我也会尝试测试第一个。我会尽快发布我的反馈。
    猜你喜欢
    • 1970-01-01
    • 2019-01-04
    • 1970-01-01
    • 1970-01-01
    • 2021-05-12
    • 1970-01-01
    • 2023-04-05
    • 2011-11-14
    • 2012-04-22
    相关资源
    最近更新 更多