开玩笑的方法调用计数是错误的吗?

时间:2019-09-06 11:33:09

标签: javascript node.js mocking jestjs

考虑代码-

// utils.js
export const foo = async (a, b) => {
   // do something
   bar(a)
}

export const bar = async (a) => {
   // do something
}

// utils.spec.js
const utils = require('./utils');

const barSpy = jest.spyOn(utils, 'bar');
const result = await utils.foo('a', 'b');

expect(barSpy).toHaveBeenCalledTimes(1);

测试失败-

Error: expect(jest.fn()).toHaveBeenCalledTimes(expected)

Expected number of calls: 1
Received number of calls: 0

我阅读了https://medium.com/@DavideRama/mock-spy-exported-functions-within-a-single-module-in-jest-cdf2b61af642https://github.com/facebook/jest/issues/936,但无法通过多个排列解决。

您对此有任何疑问吗?

2 个答案:

答案 0 :(得分:2)

如您共享的article中所述,在utils.js文件中,您正在导出具有foobar的对象。您的utils.spec.js实际上导入了exports.fooexports.bar。因此,您嘲笑exports.bar

通过如下更改utils.js,当您模拟bar时,您将模拟foo使用的实际bar。

utils.js

const bar = async () => {};
const foo = async () => {
  exportFunctions.bar();
};
const exportFunctions = {
  foo,
  bar
};
module.exports = exportFunctions;

在此codesandbox中实际操作。您可以打开一个新终端(右下角),然后在浏览器中直接运行npm test

答案 1 :(得分:1)

正如@ bhargav-shah所说,当您开玩笑地监视模块函数时,实际上是在监视其导出的函数值,而不是内部函数本身。

发生这种情况是因为commonJS模块是如何工作的。使用ES模块环境,实际上您可以在不修改代码的情况下实现您要在此处执行的操作,因为导出将是绑定。 here可以找到更深入的解释。

目前Jest不支持ES模块,因此使代码工作的唯一方法是从foo函数中调用实际导出的函数:

// utils.js
export const foo = async (a, b) => {
   // do something
   // Call the actual exported function
   exports.bar(a)
}

export const bar = async (a) => {
   // do something
}

// utils.spec.js
const utils = require('./utils');

const barSpy = jest.spyOn(utils, 'bar');
const result = await utils.foo('a', 'b');

expect(barSpy).toHaveBeenCalledTimes(1);