
在 Go 中,可通过创建独立的测试工具包(如 testutil)封装共用的 setup/teardown 逻辑,并让多个业务包的测试文件导入该工具包,从而避免代码重复。
在 go 中,可通过创建独立的测试工具包(如 `testutil`)封装共用的 setup/teardown 逻辑,并让多个业务包的测试文件导入该工具包,从而避免代码重复。
在 Go 的测试实践中,当多个包(如 foo 和 bar)需要执行相似的测试前准备(如启动 mock 服务、初始化数据库连接)和测试后清理(如关闭连接、清空临时目录)时,直接在每个包内复制 setup() 和 teardown() 函数不仅违背 DRY 原则,还会显著增加维护成本。
推荐做法是:新建一个专用测试辅助包(例如 github.com/yourorg/testutil),将共享逻辑集中管理:
// testutil/setup.go
package testutil
import (
"testing"
"os"
"database/sql"
_ "github.com/mattn/go-sqlite3" // 示例驱动
)
// SetupDB 创建并返回一个用于测试的内存 SQLite 数据库连接
func SetupDB(t *testing.T) *sql.DB {
t.Helper()
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
t.Fatalf("failed to open test DB: %v", err)
}
return db
}
// TeardownDB 关闭数据库连接
func TeardownDB(t *testing.T, db *sql.DB) {
t.Helper()
if err := db.Close(); err != nil {
t.Logf("warning: failed to close test DB: %v", err)
}
}
然后在各业务包的测试文件中直接调用:
// foo/widget_test.go
package foo
import (
"testing"
"github.com/yourorg/testutil"
)
func TestWidget_Process(t *testing.T) {
db := testutil.SetupDB(t)
defer testutil.TeardownDB(t, db)
// 使用 db 进行 widget 相关测试...
}
// bar/wingding_test.go
package bar
import (
"testing"
"github.com/yourorg/testutil"
)
func TestWingding_Render(t *testing.T) {
db := testutil.SetupDB(t)
defer testutil.TeardownDB(t, db)
// 使用 db 进行 wingding 相关测试...
}
✅ 关键注意事项:
- 工具包应使用
package testutil(非testutil_test),确保可被其他包正常导入; - 所有函数需接收
*testing.T参数并调用t.Helper(),以保证错误定位准确指向调用处而非工具包内部; - 避免在
testutil中引入生产代码依赖,保持其纯粹性与轻量性; - 若需支持不同环境(如集成 vs 单元),可结合
build tags或配置参数增强灵活性。
这种模式已被大量 Go 项目(如 Kubernetes、Docker 测试框架)采用,兼顾复用性、可读性与可维护性。










