开玩笑的测试在调用模拟的 firebase 函数之前完成,因此失败

Posted

技术标签:

【中文标题】开玩笑的测试在调用模拟的 firebase 函数之前完成,因此失败【英文标题】:jest test finishes before the mocked firebase function is called and hence fails 【发布时间】:2018-01-13 04:54:29 【问题描述】:

我正在尝试使用jest 来测试对firebase 的调用。 Firebase 是谷歌提供的在线数据库服务。我正在嘲笑firebase 模块,如下所示

'use strict';

const firebase = jest.genMockFromModule('firebase');

const ref = jest.fn(() => 
  return 
    child: jest.fn(() => 
      return ref
    ),
    update: jest.fn(() => 
      console.log('Called update')
      return Promise.resolve()
    )
  
)

firebase.initializeApp = jest.fn()
firebase.database = jest.fn(() => 
  return 
    ref: ref
  
)

module.exports = firebase

我只是在模拟我目前需要测试的功能。下面是我的测试用例。

it('+++ actionCreator addAlarm', () => 
    const store = mockStore(initialState)
    store.dispatch(ActionCreators.addAlarm(alarm));
    // Make sure that the scheduleNotifications API is called
    expect(scheduleNotifications).toHaveBeenCalled();
    expect(firebase.initializeApp).toHaveBeenCalled();
    expect(firebase.database().ref().update).toHaveBeenCalled();
);

测试用例的最后一行试图确保我正在调用被模拟的firebase update 函数。

下面是控制台输出

abcs-MBP-2:GalarmApp abc$ npm test

> GalarmApp@1.0.53 test /Users/abc/Projects/GalarmApp
> jest

 FAIL  __tests__/actionsSpecs.js
  ● >>>A C T I O N --- Test galarm actions:  › +++ actionCreator addAlarm

    expect(jest.fn()).toHaveBeenCalled()

    Expected mock function to have been called.

      at Object.<anonymous> (__tests__/actionsSpecs.js:58:52)
      at tryCallTwo (node_modules/promise/lib/core.js:45:5)
      at doResolve (node_modules/promise/lib/core.js:200:13)
      at new Promise (node_modules/promise/lib/core.js:66:3)
      at Promise.resolve.then.el (node_modules/p-map/index.js:42:16)
      at tryCallOne (node_modules/promise/lib/core.js:37:12)
      at node_modules/promise/lib/core.js:123:15

  >>>A C T I O N --- Test galarm actions:
    ✕ +++ actionCreator addAlarm (8ms)
    ✓ +++ actionCreator setConnectionStatus (4ms)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   1 passed, 1 total
Time:        1.989s, estimated 2s
Ran all test suites.
  console.warn node_modules/rn-host-detect/index.js:45
    [SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()

  console.log __mocks__/firebase.js:11
    Called update

测试用例在我检查 update 函数是否被调用的那一行失败。如果你在控制台输出中向下看,你会看到Called update控制台存在,这意味着更新函数被调用,但它是在测试用例失败后调用的。

这是addAlarm 动作,它是一个重击动作

const addAlarm = (alarm) =>  (dispatch, getState) => 
  if(alarm.status) 
    NotificationManager.scheduleNotifications(alarm);
  

  const alarmObjForFirebase = this.createAlarmObjForFirebase(alarm) 
  firebaseRef.update(alarmObjForFirebase)

据我所知,对 firebase update 函数的调用不是异步发生的。

如果您对我可以如何解决此问题有任何建议,请告诉我。

【问题讨论】:

【参考方案1】:

我在我的代码中发现了问题,并将其作为解决方案发布,以使他人受益。问题是定义 update 模拟的方式。它的定义方式是,每次我调用过去调用的 firebase.database().ref().update. Since this is a new instance of the mock function, it wouldn't contain any data aboutupdate` 函数时,我都会得到一个 update 模拟函数的新实例。

我需要修改代码如下

const update = jest.fn(() => 
  return Promise.resolve()
)

const ref = jest.fn(() => 
  return 
    update: update
  
)

这样,我不会创建 update 模拟函数的新实例,并且我能够断言它已在测试用例期间被调用。

【讨论】:

以上是关于开玩笑的测试在调用模拟的 firebase 函数之前完成,因此失败的主要内容,如果未能解决你的问题,请参考以下文章

开玩笑的预期模拟未调用(redux 组件)

不能用玩笑模拟模块,并测试函数调用

如何模拟 axios API 调用?开玩笑

如何开玩笑地模拟 VueAxios

在开玩笑的模拟模块工厂中模拟一个承诺

如何使用 pubsub 模拟器在本地调用 firebase Schedule 函数