Jest:如何计算通过`call`或`apply`调用的模拟方法的调用?

jun*_*cia 1 javascript unit-testing mocking jestjs

How can I use mocks to count function calls made via call or apply

// mylib.js
module.exports = {
  requestInfo: function(model, id) {
    return `The information for ${model} with ID ${id} is foobar`;
  },
  execute: function(name) {
    return this[name] && this[name].apply(this, [].slice.call(arguments, 1));
  },
};
Run Code Online (Sandbox Code Playgroud)
// mylib.test.js
jest.mock('./mylib.js');

var myLib = require('./mylib.js');

test('', () => {
  myLib.execute('requestInfo', 'Ferrari', '14523');
  expect(myLib.execute.mock.calls.length).toBe(1); // Success!
  expect(myLib.requestInfo.mock.calls.length).toBe(1); // FAIL
});
Run Code Online (Sandbox Code Playgroud)

If I explicitly call myLib.requestInfo, the second expectation succeeds.

Is there a way to watch module mock calls whose functions were called via apply or call?

Bri*_*ams 6

jest.mock 文档

在需要时使用自动模拟版本模拟模块。

可以通过更好地描述“自动模拟版本”的含义来改进文档,但发生的情况是Jest在用空模拟函数替换实现的同时保持模块的 API 表面相同。


所以在这种情况下execute被调用,但它已被一个空的模拟函数取代,所以requestInfo永远不会被调用,这会导致测试失败。


为了保持execute完整的实现,您将希望避免自动模拟整个模块,而是使用以下内容监视原始函数jest.spyOn

var myLib = require('./mylib.js');

test('', () => {
  jest.spyOn(myLib, 'execute');  // spy on execute
  jest.spyOn(myLib, 'requestInfo')  // spy on requestInfo...
    .mockImplementation(() => {});  // ...and optionally replace the implementation
  myLib.execute('requestInfo', 'Ferrari', '14523');
  expect(myLib.execute.mock.calls.length).toBe(1); // SUCCESS
  expect(myLib.requestInfo.mock.calls.length).toBe(1); // SUCCESS
});
Run Code Online (Sandbox Code Playgroud)