测试应优先用 os.mkdirtemp 创建唯一临时目录,失败即报错;务必 defer os.removeall 清理;路径拼接必须用 filepath.join;io 操作需抽象接口或参数化文件系统以隔离真实磁盘。

Go 测试里 os.TempDir() 返回路径不跨平台?
不是不跨平台,而是它返回的路径依赖系统环境变量(比如 TMP、TEMP、TMPDIR),在 CI 或容器里可能为空或不可写。直接拼接子目录容易 panic 或污染宿主机。
- 测试中应优先用
os.MkdirTemp("", "test-*"),它自动创建唯一临时目录并返回完整路径,失败时直接报错,比手动调os.TempDir()+os.MkdirAll()安全得多 - 别硬编码
/tmp—— Windows 上会挂,macOS 某些沙盒环境也不认 - 如果必须复用
os.TempDir(),务必加判空和可写检查:dir := os.TempDir() if dir == "" { t.Fatal("os.TempDir() returned empty string") } if err := os.WriteFile(filepath.Join(dir, ".test-write-check"), []byte("x"), 0600); err != nil { t.Fatalf("TempDir not writable: %v", err) }
测试结束后没清理 os.MkdirTemp 创建的目录?
Go 不会自动清理,漏掉会导致磁盘占满,尤其本地反复跑测试或 CI 并行任务多时特别明显。
- 必须在
defer里删,且用os.RemoveAll()(不是os.Remove()):dir, err := os.MkdirTemp("", "test-xyz-*") if err != nil { t.Fatal(err) } defer os.RemoveAll(dir) // 注意:不是 defer os.Remove(dir) - 避免在
TestMain里统一清理 —— 子测试崩溃时 defer 不触发,反而更危险 - CI 环境建议加定时清理脚本,比如 GitHub Actions 可配
post-run删除$HOME/.cache/test-*类路径
测试中读写文件却忘了设 filepath.Join()?
直接字符串拼接路径(如 dir + "/sub/file.txt")在 Windows 上会出 invalid argument 错误,因为路径分隔符不一致。
- 所有路径拼接必须用
filepath.Join():path := filepath.Join(dir, "sub", "config.json")
- 若需兼容 Windows 和 Unix 的路径断言(比如检查错误信息是否含路径),用
filepath.ToSlash()标准化后再比较:if strings.Contains(err.Error(), filepath.ToSlash(expectedPath)) { ... } - 不要用
path/filepath处理 URL 路径 —— 那是net/url的事,混用会把http://a/b解成http:a\b
Mock 文件系统操作时为什么还依赖真实磁盘?
很多测试看似用了 os.Open、ioutil.ReadFile 就以为能测逻辑,其实只是把 bug 从运行时推迟到 CI 才暴露。
立即学习“go语言免费学习笔记(深入)”;
- 真要隔离 IO,得把文件操作抽象成接口,比如定义
type FS interface { Open(name string) (File, error) },测试时传入内存实现(如memfs库) - 小项目不想引入依赖?至少把路径参数化,测试时传入
os.DirFS(dir)(Go 1.16+):func ReadConfig(fs fs.FS, name string) error { data, _ := fs.ReadFile(name) ... } // 测试: f, _ := os.MkdirTemp("", "cfg-test-*") defer os.RemoveAll(f) os.WriteFile(filepath.Join(f, "config.yaml"), []byte("..."), 0644) ReadConfig(os.DirFS(f), "config.yaml") - 注意
os.DirFS是只读的,写操作仍需真实目录 —— 别指望它帮你 mockWriteFile
临时目录的生命周期、路径构造方式、IO 抽象粒度,这三处最容易被当成“小事”跳过,结果在不同环境反复掉坑里。










