必须显式配置 run.skip-files 才能跳过 _test.go 文件,推荐使用 ".*_test\.go" 模式精确匹配所有测试文件名,该配置作用于文件名而非目录,且需注意转义点号。

默认不跳过 _test.go 文件,必须显式配置才能排除单元测试文件。 它只按目录或文件名模式过滤,不会自动识别“这是测试代码”——哪怕你用 go test 能跑通,golangci-lint 仍会照常检查 xxx_test.go 里的逻辑、错误处理、未使用变量等。
用 run.skip-files 精确匹配测试文件名
这是最常用、最可靠的方式,支持 glob 模式(注意不是正则),且对单个文件、子目录内测试文件都生效:
-
skip-files是路径前缀匹配 + 文件名后缀匹配,写.*_test\.go就能命中所有xxx_test.go和yyy_test.go - 必须用反斜杠转义点号:
.*_test\.go,写成.*_test.go会被误认为匹配_testXgo这类非法文件名 - 它只作用于文件名,不关心是否在
testdata/或internal/testutil/下,只要名字带_test.go就跳过 - 示例配置片段:
run:
skip-files:
- ".*_test\.go"
- "mock_.*\.go"为什么不用 run.skip-dirs: [testdata]?
testdata/ 目录确实该跳过,但它和单元测试文件是两回事:
-
testdata/是 Go 官方约定的“存放测试数据”的目录,里面通常放 JSON、YAML、二进制样本等,不是 Go 源码——但如果你不小心把helper_test.go放进去了,skip-dirs: [testdata]才能一并屏蔽 - 而
xxx_test.go绝大多数都和对应业务文件同级(如http/handler.go和http/handler_test.go),skip-dirs对它完全无效 - 误以为
testdata能覆盖所有测试,结果 CI 里staticcheck仍在报SA1019(比如用了弃用的bytes.Buffer.String()),其实只是测试文件没被跳过
go list 过滤方式不推荐用于跳过测试
像 golangci-lint run $(go list ./... | grep -v "_test") 这种 shell 管道写法看似灵活,实际问题很多:
立即学习“go语言免费学习笔记(深入)”;
-
go list ./...输出的是包路径(如myproj/http),不是文件路径;grep -v "_test"根本匹配不到任何东西 - 即使改成
go list -f '{{.GoFiles}}' ./...,输出格式不稳定(含引号、换行、空格),shell 解析极易出错或漏包 - 失去
golangci-lint的缓存能力:每次都要重新go list+grep,无法复用 AST 缓存,本地和 CI 都变慢 - 无法跳过
example_test.go或fuzz_test.go这类特殊测试文件,除非你手动补全所有模式
CI 和本地行为不一致?检查 skip-files 是否被覆盖
常见静默失效场景:
- 配置文件里写了
disable-all: true但没在linters.enable中补上govet或errcheck—— 此时整个 lint 流程可能提前退出,skip-files根本没机会执行 -
skip-files写在了linters-settings下(错误层级),正确位置必须是run的直系子字段 - CI 使用了
--fast模式:它会跳过staticcheck等重量级 linter,但skip-files本身仍生效;如果发现测试文件还在报错,说明是某个没被--fast屏蔽的 linter(如govet)在起作用,得确认skip-files是否真被加载 - 验证方法:加
-v参数运行一次,看日志里有没有skipping file xxx_test.go due to pattern这类提示
真正要跳过单元测试,就老老实实配 run.skip-files: ["._test\.go"]。别指望自动识别,也别绕路拼 shell,路径匹配这件事,golangci-lint 自己做得比你写脚本更稳。


















