如何使用 Jest 监视默认导出的函数?

IT技术 reactjs unit-testing mocking jestjs spy
2021-03-27 17:52:02

假设我有一个导出默认函数的简单文件:

// UniqueIdGenerator.js
const uniqueIdGenerator = () => Math.random().toString(36).substring(2, 8);

export default uniqueIdGenerator;

我会像这样使用:

import uniqueIdGenerator from './UniqueIdGenerator';
// ...
uniqueIdGenerator();

我想在我的测试中断言在保持原始功能的同时调用了这个方法。jest.spyOn但是,我会这样做,它需要一个对象以及一个函数名称作为参数。你怎么能以干净的方式做到这一点?还有一个类似的GitHub的问题jasmine兴趣的人。

6个回答

我最终放弃了默认导出:

// UniqueIdGenerator.js
export const uniqueIdGenerator = () => Math.random().toString(36).substring(2, 8);

然后我可以像这样使用和监视它:

import * as UniqueIdGenerator from './UniqueIdGenerator';
// ...
const spy = jest.spyOn(UniqueIdGenerator, 'uniqueIdGenerator');

有些人建议将它们包装在一个 const 对象中,然后将其导出。我想你也可以使用一个类来包装。

但是,如果您无法修改该类,仍然有一个(不太好)的解决方案:

import * as UniqueIdGenerator from './UniqueIdGenerator';
// ...
const spy = jest.spyOn(UniqueIdGenerator, 'default');
但这只有在 babel 通过 es6 module转换时才有效。不适用于 CommonJS
2021-05-28 17:52:02

还可以模拟导入并将原始实现作为模拟实现传递,例如:

import uniqueIdGenerator from './UniqueIdGenerator'; // this import is a mock already

jest.mock('./UniqueIdGenerator.js', () => {
  const original = jest. requireActual('./UniqueIdGenerator')
  return {
     __esModule: true,
     default: jest.fn(original.default)
  }
})

test(() => {
  expect(uniqueIdGenerator).toHaveBeenCalled()
})
实际上要感谢 jest 设置 resetMocks:true 现在默认情况下,这仅适用于第一次测试。之后default: jest.fn重置并变为undefined,因此在具有默认配置的现代笑话中,如果没有其他解决方法,这将不再有效
2021-05-22 17:52:02
这应该是公认的答案
2021-06-03 17:52:02

在某些情况下,您必须模拟导入才能监视默认导出:

import * as fetch from 'node-fetch'

jest.mock('node-fetch', () => ({
  default: jest.fn(),
}))

jest.spyOn(fetch, 'default')

仅模拟默认导出或任何其他导出,但module中的剩余导出保留为原始导出

import myDefault, { myFunc, notMocked } from "./myModule";

jest.mock("./myModule", () => {
  const original = jest.requireActual("./myModule");
  return {
    __esModule: true,
    ...original,
    default: jest.fn(),
    myFunc: jest.fn()
  }
});

describe('my description', () => {
  it('my test', () => {
    myFunc();
    myDefault();
    expect(myFunct).toHaveBeenCalled();
    expect(myDefault).toHaveBeenCalled();
    
    myDefault.mockImplementation(() => 5);
    expect(myDefault()).toBe(5);
    expect(notMocked()).toBe("i'm not mocked!");
  })
});
美丽的答案,非常有帮助。
2021-06-03 17:52:02
非常好!就个人而言,我仍然需要让默认方法返回其原始值,因此我在内部调用它,jest.fn()例如:default: jest.fn((...args) => original(...args))
2021-06-09 17:52:02

这是一种在不修改导入的情况下为默认导出执行此操作的方法(甚至根本不需要在测试中导入):

const actual = jest.requireActual("./UniqueIdGenerator");
const spy = jest.spyOn(actual, "default");