mock-fs API参考手册:mock、load、bypass、getMockRoot等8个接口速查清单

原创2026-10-23 15:49:081,411 阅读
文章标签:开发工具

mock-fs API参考手册:mock、load、bypass、getMockRoot等8个接口速查清单

mock-fs 是一个 Node.js 的内存文件系统模拟库,它可以临时接管内置的 fs 模块,让你在单元测试中用“假文件”替代真实磁盘文件,测试更快、更干净,也不再需要一大堆测试夹具。本文将速查 mock-fs 的 8 个核心接口:mock、load、bypass、restore、getMockRoot、file、directory、symlink,帮你一次看懂 API 全貌。

一、8个接口速查总览

先上一张总览表,方便按图索骥:

# 接口 作用 一句话记忆
1 mock(config, options) 启用模拟文件系统 “开机”:把 fs 指向内存
2 mock.load(path, options) 把真实文件/目录加载进模拟 “搬砖”:真文件搬到内存
3 mock.bypass(fn) 临时穿透模拟,访问真实磁盘 “开个后门”
4 mock.restore() 恢复真实文件系统 “关机”:还原 fs
5 mock.getMockRoot() 获取模拟文件系统的根目录 “查目录”
6 mock.file(properties) 创建带属性的文件工厂 精细造文件
7 mock.directory(properties) 创建带属性的目录工厂 精细造目录
8 mock.symlink(properties) 创建符号链接工厂 造快捷方式

这 8 个接口全部在 lib/index.js 中统一导出,官方完整文档见 readme.md。

二、接口逐个拆解

1. mock(config, options) —— 启用模拟文件系统

这是 mock-fs 的主入口(一个函数本身),源码见 lib/index.js。传入一个配置对象,键是相对路径,值代表文件内容或目录结构:

const mock = require('mock-fs');

mock({
  'path/to/fake/dir': {
    'some-file.txt': 'file content here',
    'empty-dir': {} // 空目录
  },
  'path/to/some.png': Buffer.from([8, 6, 7, 5, 3, 0, 9])
});

三个约定要记住:

  • 字符串 / Buffer 值 → 创建文件
  • 对象值 → 创建目录(空对象 {} 即空目录)
  • 路径一律用正斜杠 /,Windows 上也不要换反斜杠

第二个参数 options 控制两个默认目录是否创建:

选项 类型 默认值 说明
createCwd boolean true 是否为 process.cwd() 创建目录
createTmp boolean true 是否为 os.tmpdir() 创建目录

💡 不带参数直接调用 mock(),会得到一个只含 cwd 和 tmpdir 两个目录的空文件系统。

2. mock.load(path, options) —— 加载真实文件到模拟

不想手写测试数据时,可以用 load 把磁盘上的真实文件或目录“搬”进模拟文件系统,实现见 lib/loader.js。

mock({
  // 懒加载:读到时才真正读取真实内容
  'my-file.txt': mock.load(path.resolve(__dirname, 'assets/file1.txt')),

  // 预加载:立即读入内容
  'ready.js': mock.load(path.resolve(__dirname, 'scripts/ready.js'), {lazy: false}),

  // 递归加载整个目录
  'node_modules': mock.load(path.resolve(__dirname, '../node_modules'))
});

两个常用选项:

选项 类型 默认值 说明
lazy boolean true 懒加载,真正读取文件内容时才加载
recursive boolean true 是否递归加载子目录

stat 信息(时间戳、权限等)会被一并复制,所以测试里 fs.stat() 的结果和真实文件一致。

3. mock.bypass(fn) —— 穿透模拟访问真实磁盘

模拟激活期间,所有 fs 调用都打在内存上。偶尔需要读一个“只存在于真实磁盘”的文件,就交给 bypass,实现见 lib/bypass.js:

// 该文件只存在于真实文件系统
const data = mock.bypass(() => fs.readFileSync('/path/file.json', 'utf-8'));

要点:

  • 传入一个函数,函数内访问的将是真实文件系统,执行完自动恢复模拟
  • 若传入异步函数(返回 Promise),bypass 也会返回 Promise,且会在 Promise 结算后才恢复模拟
  • ⚠️ 官方提示:异步用法可能带来意外后果(其他代码在恢复前也访问了文件系统),能不异步就别异步

4. mock.restore() —— 恢复真实文件系统

调用 restore() 即可撤销 mock() 的一切效果,还原 Node 原始的 fs 绑定,源码见 lib/index.js。标准测试姿势:

beforeEach(function() {
  mock({ 'fake-file': 'file contents' });
});
afterEach(mock.restore);

📌 特别注意:在 Jest 快照测试等场景下,afterEach 里恢复太迟了,需要在断言前手动调用 mock.restore()。重复调用 restore() 是安全的。

5. mock.getMockRoot() —— 获取模拟根目录

想直接拿到内存文件系统的“根”(一个 Directory 对象)来编程式操作,就用它,源码见 lib/index.js:

const root = mock.getMockRoot();

注意:当前没有启用模拟时,它返回空对象 {},拿到的是空的 Directory。

6. mock.file(properties) —— 精细控制文件属性

字符串只能建一个“普通文件”,而 mock.file() 可以指定权限、属主、时间戳等(工厂实现见 lib/filesystem.js 附近的 file 定义,文件内部结构见 lib/file.js):

属性 类型 默认值 说明
content string | Buffer - 文件内容
mode number 0666 权限位
uid / gid number 当前用户/组 属主
atime / ctime / mtime / birthtime Date new Date() 各类时间戳
mock({
  foo: mock.file({
    content: 'file content here',
    ctime: new Date(1), // 一个“很老”的文件
    mtime: new Date(1)
  })
});

7. mock.directory(properties) —— 精细控制目录属性

目录版“属性工厂”,实现见 lib/filesystem.js,内部由 lib/directory.js 提供支撑:

属性 类型 默认值 说明
mode number 0777 权限位
uid / gid number 当前用户/组 属主
items Object - 目录内容(结构同 config)
atime / ctime / mtime / birthtime Date new Date() 各类时间戳
mock({
  'some/dir': mock.directory({
    mode: 0755,
    items: {
      file1: 'file one content',
      file2: Buffer.from([8, 6, 7, 5, 3, 0, 9])
    }
  })
});

💡 只要默认属性时,直接写对象字面量即可,不必调用 mock.directory()。

8. mock.symlink(properties) —— 创建符号链接

符号链接没有简写,必须走工厂,实现见 lib/filesystem.js,链接本体见 lib/symlink.js:

mock({
  'some/dir': {
    'regular-file': 'file contents',
    'a-symlink': mock.symlink({ path: 'regular-file' })
  }
});
属性 类型 默认值 说明
path string 必填 指向的源路径
mode number 0666 权限位
uid / gid number 当前用户/组 属主
atime / ctime / mtime / birthtime Date new Date() 各类时间戳

⚠️ 缺省 path 会直接抛出 Missing "path" property 错误,这是唯一必填项。

三、推荐测试流程:3步组合拳

把接口串起来,标准用法就三步:

  1. beforeEach 中 mock(config) —— 搭建干净环境
  2. 测试代码随意读写文件 —— 全部落在内存里
  3. afterEach 中 mock.restore() —— 还原现场

涉及真实资源时再按需加入 mock.load()(搬数据)或 mock.bypass()(穿墙读),形成闭环。

四、相关源码与文档索引

内容 路径
主入口与 8 个接口导出 lib/index.js
文件系统核心(config 解析、工厂) lib/filesystem.js
load 加载逻辑 lib/loader.js
bypass 穿透逻辑 lib/bypass.js
文件 / 目录 / 符号链接模型 lib/file.js · lib/directory.js · lib/symlink.js
官方文档(含全部示例) readme.md
测试用例参考 test/lib/index.spec.js

五、安装与注意事项

用 npm 安装(建议作为开发依赖):

npm install mock-fs --save-dev

几个容易踩的坑:

  • 引入顺序:先 require('mock-fs'),再引入其他会改动 fs 的库(如 graceful-fs),mock 才能生效
  • 版本兼容:与 graceful-fs@3.x 不兼容,4.x 可用
  • 权限控制:POSIX 系统上按文件 mode 判定访问权限;Windows 上 mode 不生效
  • 运行环境:需要 Node ≥ 12,官方在 Node 18–22 上验证过

掌握以上 8 个接口,mock-fs 的 API 你就已经全部覆盖了——剩下的就是把它写进测试,享受又快又稳的单元测试吧 🚀

登录后查看全文
mock-fs