golang自带了测试包(testing),直接能够进行单元测试、性能分析、输出结果验证等。简单看着官方文档试了试,总结一下:golang
使用golang的测试包,须要遵循简单的目录结构函数
测试代码放在待测试代码的目录下(一个包内),以_test.go结尾,例如以下目录结构,MyTest目录下有待测试的代码文件MyTest.go和测试代码MyTest_test.go性能
. |-- bin | `-- main |-- pkg | `-- darwin_amd64 | `-- MyTest.a `-- src |-- MyTest | |-- MyTest.go | `-- MyTest_test.go `-- main `-- main.go
直接在MyTest目录下执行go test命令便可,go test包含不少选项,能够参考Golang手册相关部分单元测试
待测试的MyTest.go源码以下:测试
package MyTest import ( "fmt" ) type MyStruct struct { name string } func GetFieldValue(x *MyStruct) string { value := x.name return value } func SetFieldValue(x *MyStruct, value string) { fmt.Println("SetFieldValue()") x.name = value }
对于MyTest_test.go,首先天然是要导入golang的测试包:ui
package MyTest
import testing
基本的测试函数以Test开头,后面接的字符串,第一个字符必须是数字或者大写,例如:spa
func TestMytest(t *testing.T) { var st MyStruct SetFieldValue(&st, "hello") val := GetFieldValue(&st) if val != "hello" { t.Error("Set Field") } }
T是testing包里定义的一个结构体,其包含了名为common的接口,提供了不少格式化输出的功能,golang提供了自动检查与调用测试函数的机制,测试函数的执行逻辑则须要编写者自行完成。code
执行go test 结果为:blog
Call SetFieldValue() PASS ok /go/src/MyTest 0.004s
若是写成Testmytest,运行时会直接忽略掉该函数。获得的结果仍然为Pass,可是不会打印“Call SetFieldValue()”,也就是说测试函数实际没有执行。
修改一下判断条件:接口
func TestMytest(t *testing.T) { var st MyStruct SetFieldValue(&st, "hello") val := GetFieldValue(&st) if val != "world" { t.Error("Set Field") } }
这个测试用例不会经过, 而Error函数的入参就是测试不经过时打印的信息:
SetFieldValue() --- FAIL: TestMytest (0.00s) MyTest_test.go:15: Set Field FAIL exit status 1 FAIL _/Users/ronghuihe/Documents/code/golang/my/go/src/MyTest 0.004s
这并不会中断测试程序,这个函数后面的部分仍然会执行,其余的测试函数也会执行。
testing包还自带了性能分析功能,可评估代码执行性能。性能分析函数也能够放到前面的xxx_test.go文件内,命名以Benchmark开头,如:
func BenchmarkGetFieldValue(b *testing.B) { var st MyStruct SetFieldValue(&st, "hello") for i := 0; i < b.N; i++ { GetFieldValue(&st) } }
其中b.N的值在执行过程当中会自动调整,使得循环能够执行足够屡次,以便获得较为准确的单次结果:
性能分析加-bench参数执行,即go test -bench . (不能漏了最后这个点,它表示执行全部的性能测试函数)
BenchmarkGetFieldValue SetFieldValue() SetFieldValue() SetFieldValue() SetFieldValue() SetFieldValue() SetFieldValue() 2000000000 0.55 ns/op
每次循环大约须要0.55ns。这里SetFieldValue()打印了屡次,是由于BenchmarkGetFieldValue被调用了屡次。
分析testing包的源码benchmark.go里的launch函数和runN函数,能够看到golang会自行调节性能分析函数的调用次数。每次执行runN都会执行一次性能测试函数,然后根据运行时间,会肯定后续的内部循环执行次数b.N,直到总的运行时间达到go test -benchtime指定的时间(若是没指定默认为1s)
注意统计时间时,执行的是使用者编写的性能分析函数,如上例中的BenchmarkGetFieldValue,而最后输出的结果,表达的是for循环里函数的性能,所以for循环以前的代码执行时间很长的话,可能致使统计偏差比较大,若是须要剔除for以前代码的影响,能够在for循环以前调用ResetTimer()接口重置本次统计的时间值:
func BenchmarkGetFieldValue(b *testing.B) { var st MyStruct SetFieldValue(&st, "hello") b.ResetTimer() for i := 0; i < b.N; i++ { GetFieldValue(&st) } }