发布于2026-07-07 阅读(0)
扫一扫,手机访问
首先要搞清楚一个核心前提:单元测试一旦依赖了数据库、HTTP客户端或消息队列,那就不是单元测试了。很多团队在这个问题上反复踩坑——测试函数里直接调*sql.DB、发真实HTTP请求、甚至连接线上Redis,结果就是测试跑得慢、不稳定、还互相干扰。真正的单元测试应该像手术刀一样精准:只测当前函数的逻辑,外部依赖全部被挡在门外。
那么怎么做?几个关键点:
第一,用t.Parallel()开启并发执行,但这有个硬前提——测试之间不能共享任何可变状态。第二,依赖接口抽象。比如别把*sql.DB直接塞进被测函数,而是定义一个OrderRepository接口,测试时传入内存实现或mock。第三,避免在测试里启动真实服务。如果需要验证序列化逻辑,直接用json.Marshal/json.Unmarshal,配合结构体字段断言就足够了。第四,千万不要在init()或包级变量里做初始化操作——它们会在所有测试前运行,一旦出错整个测试套件都会崩,隔离性荡然无存。
集成测试需要跑真实组件(比如PostgreSQL、RabbitMQ),但绝不能把开发机变成测试沙盒。最常见的错误是硬编码localhost:5432,或者直接复用生产配置。正确的做法应该是:
go test -tags=integration控制开关,确保integration构建标签只在CI或明确命令下生效,日常go test不会触发这些测试。docker run --rm -d -p 5432:5432 -e POSTGRES_PASSWORD=pass postgres:15拉起临时数据库,测试完成自动销毁,干净利落。os.Getenv("TEST_DB_URL"),本地开发就设为postgres://test:test@localhost:5432/test?sslmode=disable。public schema,否则数据残留会导致莫名其妙的失败。Go Micro的rpc和broker机制让集成测试的复杂度上了一个台阶——你不能只测一个服务,还得验证跨服务调用是否真正触发、数据是否正确流转。这里有几个实用技巧:
micro.NewService(micro.Registry(registry.NewRegistry()))内置内存注册器,省去启动Consul或Etcd的麻烦。broker.Publish行为,用broker.NewMemoryBroker()捕获发出去的消息,然后断言topic、payload、headers是否如预期。service.Server().Options().Address获取监听地址,再构造micro.NewClient()。processing,这才是集成测试该关心的事。go test -cover跑出来的覆盖率数据很容易给人虚假的安全感,尤其是错误路径覆盖严重不足。很多团队报告85%覆盖率,结果上线后网络一超时直接panic。问题的根源在于,大部分人的测试只走了happy path。
要想真正覆盖错误处理:
{name: "db timeout", mock: func() error { return context.DeadlineExceeded }, wantErr: true}。go test -coverprofile=c.out && go tool cover -func=c.out查看具体哪行没被覆盖,重点关注if err != nil块内的逻辑。call方法,模拟micro.ErrCallTimeout或micro.ErrServiceNotFound,并验证fallback行为是否合规。实际项目里最难的从来不是写测试,而是决定哪些逻辑值得测、哪些mock能信、哪些集成场景必须走通。边界模糊的时候,优先保住核心流程的端到端验证,而不是堆砌覆盖率数字。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8