如何将Jest中重复的getCalculatedValues Mock提取到工具文件中?
我太懂这种重复写Mock的烦躁了!Jest的手动Mock功能就是专门解决这类代码重复问题的,我来一步步带你搞定它:
第一步:搭建手动Mock的目录结构
首先,你需要在和你的utils.js同级的位置,创建一个名为__mocks__的文件夹(注意前后都是双下划线),然后在这个文件夹里新建一个和原文件同名的utils.js。比如你的项目结构会变成这样:
你的项目/ utils.js usage.js __mocks__/ utils.js usage.test.js otherFile.test.js // 其他用到getCalculatedValues的测试文件
第二步:编写通用的Mock逻辑
在__mocks__/utils.js里,你要按照原模块的导出结构来写Mock代码——原utils.js导出的是一个函数getCalculatedValues,这个函数调用后返回对象,所以你的Mock也得是一个函数,返回你预设的固定值:
// __mocks__/utils.js export const getCalculatedValues = jest.fn(() => ({ val1: 123, val2: 321, // 这里可以添加所有你需要的默认Mock字段 }));
这里用jest.fn()的好处是,后续你还能在单个测试用例里修改它的返回值,或者断言它是否被调用、调用参数是什么。如果不需要这些功能,也可以直接写普通函数:
export const getCalculatedValues = () => ({ val1: 123, val2: 321, });
第三步:在测试文件里复用这个Mock
现在你不用再在每个测试文件里重复写冗长的jest.mock回调了,只需要一行简单的代码,Jest会自动去__mocks__目录找对应的Mock文件:
// usage.test.js import { doSomething } from './usage'; import { getCalculatedValues } from './utils'; // 这一行就够了,Jest会自动加载__mocks__/utils.js jest.mock('./utils'); it('Should return mock values', () => { const res = doSomething(); expect(res.val1).toEqual(123); // 还能顺便断言函数调用情况 expect(getCalculatedValues).toHaveBeenCalledWith('some-val'); });
其他需要用到这个Mock的测试文件,只需要复制这行jest.mock('./utils')就行,完全不用重复写Mock对象的内容。
第四步:单个测试用例自定义Mock值
如果某个测试需要特殊的返回值,你也可以在该测试文件里覆盖默认的Mock:
// 比如某个测试需要val1是456 it('Should use custom mock values', () => { getCalculatedValues.mockReturnValue({ val1: 456, val2: 654 }); const res = doSomething(); expect(res.val1).toEqual(456); });
顺便纠正个小问题
你之前的Mock写法其实有个隐藏bug:原getCalculatedValues是函数,你却把它Mock成了对象,调用的时候会报错“not a function”——能通过测试可能是巧合?现在用上面的方法就能避免这个问题,保证Mock的结构和原模块完全一致。
备注:内容来源于stack exchange,提问作者physicsboy

