embed.fs和os.dirfs不可用于磁盘读写mock,因前者只读、后者不支持目录创建;真正可用的是基于sync.map和filepath.clean实现的并发安全fakefs,需统一路径分隔符、归一错误类型并保留context参数。

为什么不能直接用 embed.FS 或 os.DirFS 做磁盘读写 Mock
embed.FS 是只读的,传给需要 WriteFile 的函数会 panic;os.DirFS 虽然能读,但不处理目录创建,调用 Save("a/b/c.txt") 时因父路径不存在直接失败。这两者都不是「可写沙箱」,只是文件系统快照或只读视图。
真正可用的沙箱 Mock 方式:FakeFS + 路径标准化 + 并发安全 map
核心是自己实现一个内存型 Storage 接口(不是 fs.FS),所有方法都基于 sync.Map 存储,并强制对路径做 filepath.Clean 处理——否则测试里传 "./config/../data.json",线上跑 "data.json",行为不一致。
-
WriteFile(ctx, path, data, perm):先filepath.Clean(path),再存入sync.Map,key 为清理后路径,value 为struct{ data []byte; modTime time.Time; perm fs.FileMode } -
ReadFile(ctx, path):同样 clean 后查 map,未命中返回ErrNotFound(不是os.ErrNotExist) -
Delete(ctx, path):clean 后 delete map key,不递归删子路径(保持语义简单) -
Stat(ctx, path):返回自定义FileStat,含Name()、Size()、IsDir()、ModTime(),避免伪造fs.FileInfo
Mock 时最容易漏掉的三件事
业务代码在沙箱里跑得通,不代表上线就稳——很多坑藏在路径、错误、并发细节里:
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
- 没统一处理路径分隔符:
filepath.Clean在 Windows 返回,Linux 返回/,FakeFS 必须统一转成/存储,否则Exists("a/b.txt")和Exists("a\b.txt")查不到同一份数据 - 错误类型没归一:
os.IsNotExist(err)判定不了你 Fake 实现返回的ErrNotFound,必须让业务代码用接口定义的错误变量判断 - 没加 context 控制:
WriteFile方法签名里漏掉ctx context.Context,导致超时逻辑无法注入,沙箱里测不出阻塞问题
如何验证 FakeFS 真正隔离了磁盘依赖
最硬核的验证方式是:把业务代码里所有 os. 调用全部删掉,只保留对 Storage 接口的调用,然后跑一遍单元测试 —— 如果全过,且 go test -cover 显示覆盖了读/写/删/查存在/Stat 全路径,说明磁盘已彻底脱钩。
注意:不要在 Fake 实现里调用任何 os. 函数(包括 os.TempDir()),哪怕只是用来生成临时路径。Fake 就该是纯内存、无副作用、可预测的。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










