Go单元测试——资源初始化

1,436 阅读2分钟

Go项目本身会依赖一些第三方资源,比如MySQL、Redis等。单元测试的时候,如果遇到内部调用资源的方法,一般有两种解法:

  1. Mock 假数据,这种方式对代码的编写结构有要求。比如,资源最好使用依赖注入的模式、面向接口编程。
  2. 在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 ./...