ast包仅提供AST只读表示,无法直接生成测试桩;需结合go/ast解析、手动构建节点、go/format格式化及go/token.FileSet支持,才能生成合法Go测试代码。

ast包不能直接生成测试桩,得靠go/ast + go/format组合解析+重写
Go 的 ast 包本身不提供“生成 mock”或“插入测试桩”的能力,它只是语法树的只读表示。想基于源码自动生成单元测试桩(比如为某个函数补一个 TestXXX 函数),必须手动用 go/ast 解析 AST,再用 go/format 和 go/token 生成合法 Go 代码并写入文件。这不是一键命令,而是代码生成逻辑。
用ast.ParseFiles解析源文件时,必须传入完整包路径而非相对路径
常见错误是传 "./handler.go" 导致 ast.ParseFiles 返回空文件或 panic。它实际需要的是 Go 包导入路径(如 "myproject/handler"),且该路径下必须有 go.mod 或能被 go list 识别。否则解析失败,后续所有生成都无从谈起。
- 正确做法:先用
go list -f '{{.Dir}}' myproject/handler获取绝对路径,再传给ast.ParseFiles - 若目标文件在
internal/下,需确保调用方模块能 import 它,否则go list会报错 - 别依赖
filepath.Walk扫描 .go 文件后直接 parse —— 缺少包上下文会导致 import 路径解析失败
生成Test函数时,函数签名必须匹配被测函数的接收者和参数类型
比如被测函数是 func (s *Service) Do(ctx context.Context, req *Request) error,自动生成的测试函数不能写成 func TestService_Do(t *testing.T) 就完事——它缺了对 s 的构造、ctx 和 req 的初始化逻辑。AST 只能告诉你签名,不能推导依赖如何构造。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 必须提取接收者类型(如
*Service)并检查其是否实现了可 mock 的接口;否则只能生成空桩,无法真正运行 - 参数中含
context.Context、*http.Request、io.Reader等,需硬编码默认值(如context.Background())或留占位符注释(如// TODO: init req) - 返回值含 error 时,建议默认断言
require.NoError(t, err),而非assert.NoError—— 避免后续 nil 指针 panic
生成 mock 接口实现时,gomock 不支持 ast 自动生成,必须用 mockgen
有人误以为解析出 interface 定义后,就能用 ast 写个函数把它的方法转成 mock 结构体。这是徒劳的:gomock 的 mockgen 工具才是唯一受支持的生成方式,它内部也用 go/ast,但封装了完整的类型系统检查、包依赖分析和模板渲染。自己手写 mock 类型极易出错,且无法通过 gomock.Controller 生命周期管理。
立即学习“go语言免费学习笔记(深入)”;
- 正确流程:先用
ast找到目标 interface 名(如UserRepository),再执行mockgen -source=repo.go -destination=mocks/mock_repo.go -package=mocks - 生成命令中的
-package必须与目标目录的package声明严格一致,否则测试文件 import 时会报undefined: NewMockUserRepository - 不要试图用
ast.Inspect改写原文件插入mock.NewController—— 这属于测试逻辑,应由开发者在_test.go中手写
//go:generate mockgen 注释)来驱动,纯 ast 无法闭环。

















