Go项目本身会依赖一些第三方资源,比如MySQL、Redis等。单元测试的时候,如果遇到内部调用资源的方法,一般有两种解法:
- Mock 假数据,这种方式对代码的编写结构有要求。比如,资源最好使用依赖注入的模式、面向接口编程。
- 在TestMain中初始化依赖的资源对象,单测中直接依赖真是的数据。
这里主要介绍第二种解法,工程项目一般都包含三个环境:开发、预发、线上,对应的也有三个配置文件。因为环境隔离的原因,每个环境依赖的资源也会有所不同。我们需要在单测之前,使用配置文件,将单测依赖的资源对象进行初始化。
├── api
│ └── cmd
| └── main.go
├── conf
│ ├── daily
│ │ └── config.toml
│ ├── prepub
│ │ └── config.toml
│ └── publish
│ └── config.toml
├── server
├── data
├── utiltest
| └── bootstrap.go
└── ......
TestMain
TestMain 是一个特殊的函数,测试用例执行的时候,会先执行 TestMain 函数,然后可以在 TestMain 中调用 m.Run() 函数来执行普通的测试函数。我们在m.Run()函数前做准备逻辑,在m.Run()后做清理逻辑。
func TestMain(m *testing.M) {
//准备工作
fmt.Println("start prepare")
exitCode := m.Run()
//清理工作
fmt.Println("prepare to clean")
os.Exit(exitCode)
}
现在只需要在 TestMain 中初始化配置文件就可以了。但 TestMain 中如何找到配置文件的路径呢?一般工程项目会涉及到多个开发者,每个人本地的工程路径都是不相同的。直接使用某一个开发的绝对路径的话,没有办法做到通用。
确认配置文件路径
Go语言中,通过调用 runtime 下函数 Caller可以定位到文件的绝对路径。而有了这个绝对路径,我们就可以通过相对路径来确定配置文件的位置。
Caller 接受一个调用栈的参数,如果传递0,输出就是当前的文件所在的路径,而且是绝对路径。参数1表示调用者的调用者,随着数字的增大,调用层级也就越上层。现在我们有了当前文件的绝对路径,又知道它和配置文件的相对路径,当然就可以确定配置文件的路径了。
// file: utiltest/bootstrap.go
func GetConfigPath() string {
_, filename, _, _ := runtime.Caller(0)
dir := filepath.Dir(filename)
// 根据 dir 和 配置文件的相对位置,返回绝对位置
i := strngs.LastIndex(dir, "utiltest")
confPath := dir[0:i] + "conf/daily/config.toml"
return confPath
}
Go 中日志的打印一般会包括文件的名称、代码的行号、日志信息。而有些地方因为不合理的封装,导致我们输出的错误信息都是同一个文件的同一行,非常不利于排查问题,Caller 就可以用来解决这个问题。
执行单测
提交代码前,执行项目下的所有单测文件,确保修改没有对历史单测造成影响。
go test -v ./...