使用带有 jest.spyOn 的 react-hooks-testing-library - 不调用间谍

Using react-hooks-testing-library with jest.spyOn - spy is not called

我在设置单元测试以确定是否使用正确参数调用函数时遇到问题。 useAHook returns 调用函数 bar 的函数 foo。代码看起来像这样

//myModule.js
export const useAHook = (arg1, arg2) => {
  const foo = useCallback(() => {
    bar(arg1, arg2);
  }, [arg1, arg2]);

  return foo;
}

export const bar = (a, b) => {
   //does some stuff with a and b
}

我正在尝试使用 renderHookjest.spyOn 对该代码进行单元测试。我想确认调用函数 foo 会导致使用正确的参数调用 bar。我的单元测试看起来像这样

//myModule.spec.js

import * as myModule from './myModule.js'

it('should call foo with correct arguments', () => {
  const spy = jest.spyOn(myModule, 'bar');
  const { result } = renderHook(() => myModule.useAHook('blah', 1234));
  const useAHookFunc = result.current;

  useAHookFunc();

  // fails, spy is not called
  expect(spy).toBeCalledWith('blah', 1234);
});

结果是测试失败,表示从未调用 spy。我是不是哪里做错了,还是没有正确使用任何一个工具?

这一行:

import * as myModule from './myModule.js'

...将 myModule.js 的模块绑定导入 myModule.

然后这一行:

const spy = jest.spyOn(myModule, 'bar');

...在间谍中为 bar 包装 模块导出 ...

...但是间谍永远不会被调用,因为 useAHook 不会为 bar 调用 模块导出 ,它只会调用 bar直接。


如果您修改 useAHook 以调用 bar 的模块导出,那么间谍将被调用。

有几种方法可以做到这一点。

您可以将 bar 移动到它自己的模块中...

...或者您可以导入 myModule.js 的模块绑定,这样您就可以调用 bar 的模块导出:

import { useCallback } from 'react';

import * as myModule from './myModule';  // <= import the module bindings

export const useAHook = (arg1, arg2) => {
  const foo = useCallback(() => {
    myModule.bar(arg1, arg2);  // <= call the module export for bar
  }, [arg1, arg2]);

  return foo;
}

export const bar = (a, b) => {
   //does some stuff with a and b
}

我设法窥探了 hook 导出方法(使用 import * as),然后将模拟函数注入到实现中:

import * as useThingHook from 'useThing'

it('a test', () => {
  const methodMock = jest.fn()
  jest.spyOn(useThingHook, 'usething').mockImplementation(() => ({
    method: methodMock
  }))

  act()

  expect(methodMock).toHaveBeenCalled()
})