如何使用Jest正确mock FileReader解决测试中回调未覆盖的问题
问题本质
当前mock逻辑没有打通FileReader的事件触发链路:
- 你定义的
FileReaderMock中,onload被初始化为空的jest mock函数,readAsText也只是空的jest.fn(),没有任何实际行为 - 业务代码执行时,虽然会把自定义的onload处理函数赋值到
f.onload属性上,但整个测试流程从未触发这个回调,导致callback(e.target.result)这段逻辑从来没有被执行过,自然会被覆盖率标记为未覆盖。
修复方案
需要在mock层补完两个核心行为:
- 不要把
onload初始化为空的jest.fn(),避免业务代码绑定回调时被无效的mock占位影响 - 补全
readAsText的mock实现逻辑,让它可以模拟文件读取完成的流程,主动触发绑定好的onload回调
修正后的测试代码示例
const { testFunction } = require("./index"); class FileReaderMock { DONE = FileReader.DONE; EMPTY = FileReader.EMPTY; LOADING = FileReader.LOADING; readyState = 0; error = null; result = null; abort = jest.fn(); addEventListener = jest.fn(); dispatchEvent = jest.fn(); onabort = jest.fn(); onerror = jest.fn(); // 不再初始化为jest.fn(),允许业务代码正常绑定自定义回调 onload = null; onloadend = jest.fn(); onloadprogress = jest.fn(); onloadstart = jest.fn(); onprogress = jest.fn(); // 重写readAsText的实现,替代原有的空jest.fn() readAsText = jest.fn((blob) => { // 模拟文件读取完成的逻辑:设置返回值、构造事件、触发onload this.result = "mock读取得到的文本内容"; const mockEvent = { target: { result: this.result } }; this.onload(mockEvent); }); readAsArrayBuffer = jest.fn(); readAsBinaryString = jest.fn(); readAsDataURL = jest.fn(); removeEventListener = jest.fn(); } const mockCallback = jest.fn(); describe("testFunction", () => { const fileReader = new FileReaderMock(); // 每个测试前重置mock状态,避免用例间的污染 beforeEach(() => { jest.clearAllMocks(); fileReader.onload = null; fileReader.result = null; }); jest.spyOn(window, "FileReader").mockImplementation(() => fileReader); it("should be called mockCallback and readAsText with the blob value", () => { const uintArray = new Uint8Array(); testFunction(uintArray, mockCallback); expect(mockCallback).toHaveBeenCalledWith("mock读取得到的文本内容"); expect(fileReader.readAsText).toHaveBeenCalledWith(new Blob([uintArray])); }); });
可选简化方案
如果不想在readAsText的mock里内置自动触发逻辑,也可以在测试用例里手动触发绑定好的onload回调,效果完全一致:
it("should be called mockCallback and readAsText with the blob value", () => { const uintArray = new Uint8Array(); testFunction(uintArray, mockCallback); // 手动模拟onload事件触发 fileReader.onload({ target: { result: "自定义测试返回值" } }); expect(mockCallback).toHaveBeenCalledWith("自定义测试返回值"); expect(fileReader.readAsText).toHaveBeenCalledWith(new Blob([uintArray])); });
调整完成后,业务代码中onload内部的回调逻辑会被完整执行,覆盖率统计可以正常识别这部分代码。
内容的提问来源于stack exchange,提问作者itwaze
相关产品推荐
相关产品推荐

