使用Jest为导入的工具函数/自定义hook模拟多返回值的最佳方案
现有实现的问题
你当前代码里的useCount.jest.fn()写法是错误的,jest.fn()不是挂载在原hook函数上的方法,代码直接运行会抛出异常。
模拟方案选择
两种方式的适用场景和写法如下:
1. 全量模拟(不需要用到原hook实现时推荐)
如果你所有测试都不需要调用useCount的原始逻辑,直接用jest.mock做模块级模拟即可,写法最简单:
// 测试文件最顶部,所有import语句之前声明 jest.mock('../../hooks/useCount') import { useCount } from '../../hooks/useCount' import { ListItems } from '../ListItems' const fruits = [ 'Apple', 'Banana', 'Cherry', 'Dragonfruit', 'Elderberry', 'Fig', 'Grape', 'Huckleberry', 'Icaco', 'Jujube', ] // 全局设置默认返回值,每次测试前重置避免用例之间互相影响 beforeEach(() => { useCount.mockReturnValue({ count: fruits.length + 1 }) }) describe(ListItems, () => { test('renders all items if count is greater than number of items', () => { const { getByText } = render(<ListItems items={fruits} />) // 断言逻辑和你原代码一致 }) test('renders the correct items if count is less than the number of items', () => { // 单测单独指定返回值,写法和你的预期一致 useCount.mockReturnValueOnce({ count: 5 }) const { getByText } = render(<ListItems items={fruits} />) // 断言逻辑和你原代码一致 }) })
2. spyOn 模拟(需要保留原hook实现时推荐)
如果你有部分测试需要用到useCount的原始逻辑,用jest.spyOn更灵活,还可以随时恢复原实现:
import * as useCountModule from '../../hooks/useCount' import { ListItems } from '../ListItems' const fruits = [/* 水果数组同上 */] const mockUseCount = jest.spyOn(useCountModule, 'useCount') beforeEach(() => { // 重置mock状态,设置默认返回值 mockUseCount.mockReset().mockReturnValue({ count: fruits.length + 1 }) }) // 如果你需要恢复原实现,调用 mockUseCount.mockRestore() 即可
Flow 类型冲突解决方案
冲突的原因是Flow无法识别普通函数被替换为Jest Mock函数的类型,三种解决方法:
- 优先推荐用
spyOn写法,jest.spyOn返回值本身就是Jest Mock类型,不需要额外处理就能兼容Flow类型校验 - 手动做类型转换:
const mockUseCount = (useCount: JestMockFn<[], {count: number}>) // 后续调用 mockUseCount.mockReturnValueOnce 不会报类型错误 - 临时忽略类型校验,在对应行加Flow注释:
// $FlowFixMe jest mock 类型特殊处理,忽略校验 useCount.mockReturnValueOnce({ count: 5 })
内容的提问来源于stack exchange,提问作者warrenbuffering
相关产品推荐
相关产品推荐

