mock filereader 的关键是替换全局构造函数并控制其异步事件与状态。需模拟 readasdataurl 行为,手动触发 onload/error 事件并设置 result、readystate 等属性,不可仅 mock 方法。

在 JavaScript 单元测试中 Mock FileReader,核心是**替换全局 FileReader 构造函数,控制其异步行为(如 readAsDataURL)触发的 load 或 error 事件,并手动设置 result 属性**。不能只 mock 方法,必须 mock 整个类实例的行为。
1. 基础 Mock:替换构造函数 + 模拟成功读取
适用于测试文件内容被正确解析并赋值的逻辑(比如预览图片):
// Jest 示例
beforeEach(() => {
// 保存原构造函数,便于恢复
global.FileReader = class {
constructor() {
this.result = '';
this.readyState = 0; // EMPTY
}
readAsDataURL(file) {
// 模拟异步完成
setTimeout(() => {
this.result = `data:${file.type};base64,abc123`;
this.readyState = 2; // DONE
this.onload && this.onload({ target: this });
}, 0);
}
};
});
afterEach(() => {
// 恢复原生 FileReader(可选,Jest 默认每个 test 隔离)
delete global.FileReader;
});
2. 可控 Mock:支持 success / error / abort 分支
更健壮的写法,让测试能覆盖不同状态:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用 jest.fn() 记录调用,或用 jest.mock() 替换整个类
- 暴露一个“触发事件”的方法,由测试用例决定触发哪个回调
- 手动设置
result、error、readyState等关键属性
// 使用 Jest mock 类
jest.mock('path-to-your-component', () => {
const original = require.requireActual('path-to-your-component');
return {
...original,
// 在组件内 new FileReader() 时返回可控实例
};
});
// 更推荐:直接 mock 全局 FileReader 类
global.FileReader = class MockFileReader {
constructor() {
this.result = null;
this.error = null;
this.readyState = 0;
this.onload = null;
this.onerror = null;
this.onabort = null;
}
readAsDataURL(file) {
this.readyState = 1; // LOADING
// 不自动触发,由测试手动调用
}
// 测试中可调用:
triggerLoad(resultValue = 'data:text/plain;base64,test') {
this.result = resultValue;
this.readyState = 2;
if (this.onload) this.onload({ target: this });
}
triggerError(message = 'Failed to read file') {
this.error = { name: 'Error', message };
this.readyState = 0;
if (this.onerror) this.onerror({ target: this });
}
triggerAbort() {
this.readyState = 0;
if (this.onabort) this.onabort({ target: this });
}
};
3. 实际测试用例示例
假设你有这样一个上传处理函数:
function handleFile(file) {
const reader = new FileReader();
reader.onload = () => {
document.getElementById('preview').src = reader.result;
};
reader.readAsDataURL(file);
}
对应测试:
test('should set preview src when file is read successfully', () => {
const file = new File(['hello'], 'test.txt', { type: 'text/plain' });
handleFile(file);
// 触发模拟的 onload
const reader = global.FileReader.mock.instances[0];
reader.triggerLoad('data:text/plain;base64,SGVsbG8=');
expect(document.getElementById('preview').src).toBe('data:text/plain;base64,SGVsbG8=');
});
test('should handle read error', () => {
const file = new File([''], 'empty.txt');
handleFile(file);
const reader = global.FileReader.mock.instances[0];
reader.triggerError('Security error');
// 断言错误处理逻辑,例如显示提示、清空状态等
});
4. 注意事项与避坑点
-
不要只 mock
readAsDataURL方法:FileReader 的事件机制依赖实例状态(result,readyState),仅 mock 方法无法触发onload -
确保
onload是在setTimeout或 Promise 中触发:因为真实 FileReader 是异步的,同步触发可能绕过事件循环,导致断言时机错误 -
Jest 中慎用
jest.resetModules():如果 FileReader 被模块缓存,重置后需重新 mock -
TypeScript 用户注意类型声明:可在
declare global中补充FileReader的 mock 类型,避免 TS 报错
Mock FileReader 的关键是把它当作一个需要完全可控的异步对象来对待——控制它的状态、结果和事件分发时机,而不是仅仅拦截某个方法调用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










