测试中直接读写真实文件会破坏隔离性、引发并发冲突和权限问题;应使用os.MkdirTemp创建临时路径并defer os.RemoveAll清理;通过io.Reader/io.Writer接口解耦,用strings.NewReader或io.Pipe模拟输入,避免内存暴涨与fd泄露。

用 ioutil.ReadFile 和 os.WriteFile 做简单测试会踩哪些坑
直接在测试里读写真实文件路径,看似快,实则破坏测试隔离性。比如并发跑测试时多个 goroutine 同时写 test.txt,结果不可控;CI 环境没写权限还会 panic。
真正安全的做法是:每次测试前生成唯一临时路径,用完立刻清理。别依赖固定路径或当前目录。
- 用
os.MkdirTemp("", "test-")创建临时目录,返回路径和可能的错误 - 测试末尾务必调用
os.RemoveAll(tempDir),建议用defer包裹 - 避免硬编码
"./data"或"/tmp/test"—— 这些在 Docker 容器或 Windows 下行为不一致
如何用 io.Reader / io.Writer 接口解耦文件操作
把具体文件操作封装进函数参数,而不是在函数内部直接调用 os.Open 或 os.Create,测试时就能传入 bytes.Buffer 或 strings.NewReader 替代真实文件句柄。
例如处理配置文件的函数,不要这样写:
立即学习“go语言免费学习笔记(深入)”;
func LoadConfig() (map[string]string, error) {
f, _ := os.Open("config.yaml")
defer f.Close()
// ...
}
而应该改成:
func LoadConfig(r io.Reader) (map[string]string, error) {
data, _ := io.ReadAll(r)
return parseYAML(data)
}
- 测试时传
strings.NewReader("key: value"),完全跳过磁盘 I/O - 生产调用时用
os.Open("config.yaml")作为r - 注意:
io.Reader不支持Seek,如果逻辑需要重读(如解析 JSON 多次),得先用io.ReadAll转成[]byte
用 os.File 模拟失败场景(权限拒绝、文件不存在)
真实错误很难稳定复现,但可以用 os.ErrPermission、os.ErrNotExist 等预定义变量手动构造错误,验证你的错误处理分支是否健壮。
里面有2个文件夹。其中这个文件名是:finishing,是我项目还没有请求后台的数据的模拟写法。请求后台数据之后,瀑布流的js有一点点变化,放在文件名是:finished。变化在于需要穿参数到后台,和填充的内容都用后台的数据填充。看自己项目需求来。由于chrome模拟器是不允许读取本地文件json的,所以如果你要进行测试,在hbuilder打开项目就可以看到效果啦,或者是火狐浏览器。
比如你写了这样的逻辑:
if errors.Is(err, os.ErrNotExist) {
return defaultConfig
}
测试它不能只靠删掉文件再运行——CI 可能没权限删,或者删了别的测试会崩。更稳的方式是 mock 返回值:
- 把文件操作包装成可注入的函数类型,如
type FileReader func(name string) ([]byte, error) - 测试中传入闭包:
func(_ string) ([]byte, error) { return nil, os.ErrNotExist } - 避免用
os.Rename或os.Chmod改系统状态来触发错误——副作用大、难清理
测试大文件读写时为什么不能用 bytes.Buffer 全量加载
bytes.Buffer 本质是内存 slice,模拟几百 MB 文件会导致测试内存暴涨甚至 OOM,而且掩盖了流式处理的真实问题(比如未检查 io.EOF、缓冲区未 flush)。
正确做法是用 io.Pipe 搭建可控的流管道:
pr, pw := io.Pipe()
go func() {
defer pw.Close()
io.Copy(pw, sourceReader) // sourceReader 可以是文件、网络响应等
}()
// 把 pr 当作输入传给被测函数
process(pr)
-
io.Pipe是惰性执行,不会一次性把所有数据 load 到内存 - 可以控制写入速度(加
time.Sleep)、中途关闭(pw.Close()触发io.ErrClosedPipe) - 注意:别漏掉
pw.Close(),否则pr.Read会永远阻塞
真实文件测试里最容易被忽略的,是忘记验证 Close() 是否被调用 —— 尤其是 *os.File,不关会导致 fd 泄露,在长时间运行的服务里迟早出事。









