golang从语言层面支持了单元测试。
只要把代码文件和测试函数按照指定的规则命名,就能实现自动化的测试。
测试可以分为功能测试和性能测试,下面分别来说明。
功能测试
golang规定所有测试代码必须放在以"_test.go"结尾的文件中。
测试函数必须以Test开头,紧跟的字符串首字符必须是大写字母或数字,参数为testing包的T类型指针。
我们可以写一个Hello()函数并使用TestHello()函数来测试。
Hello()定义在hello.go中:
-
package hello
-
-
import (
-
"fmt"
-
)
-
-
func Hello() {
-
fmt.Printf("hello world\n")
-
}
TestHello()定义在hello_test.go中,该文件和hello.go放在相同目录下:
-
package hello
-
-
import (
-
"testing"
-
)
-
-
func TestHello(t *testing.T) {
-
Hello()
-
}
执行go test命令,测试工具会自动完成代码编译和运行。打印结果:
-
# go test
-
ok command-line-arguments 0.003s
下面再来看一个更实际的例子:
定义一个Add()函数,使用TestAdd()来测试Add()函数的功能。
可以使用testing包的T类型方法来帮助我们显示测试结果。
# cat add_test.go
-
package hello
-
-
import "testing"
-
-
func TestAdd1(t *testing.T) {
-
if Add(2, 4) == 6 {
-
t.Log("test add1 passed")
-
} else {
-
t.Error("test add1 failed")
-
}
-
}
运行go test会运行目录下所有的测试函数,也可以指定一个测试文件:
或是指定测试的函数:
输出结果:
-
# go test -run="TestAdd1"
-
PASS
-
ok github.com/vv1133/golang_example/test 0.005s
我们发现,用t.Log()打印的内容并没有显示出来,这是因为默认情况下Log级别的打印不会被输出到控制台,可以用-v参数来显示更详细的测试信息。
-
# go test -run="TestAdd1" -v
-
=== RUN TestAdd1
-
--- PASS: TestAdd1 (0.00s)
-
add_test.go:7: test add1 passed
-
PASS
-
ok github.com/vv1133/golang_example/test 0.003s
另一个测试的方法是使用Example前缀。
go测试工具会自动捕获这些函数的标准输出,并和注释中以“Output:”开头的内容比较,如果相同则测试通过。
-
func ExampleHello_test1() {
-
Hello()
-
// Output: hello world
-
}
-
# go test -run="ExampleHello_test1" -v
-
=== RUN ExampleHello_test1
-
--- PASS: ExampleHello_test1 (0.00s)
-
PASS
-
ok github.com/vv1133/golang_example/test 0.004s
性能测试
性能测试函数需要以Benchmark作为函数名前缀,后接的字符串首字符必须是大写字母或数字。参数是testing包中的类型B。
-
func BenchmarkHello(b *testing.B) {
-
for i := 0; i < b.N; i++ {
-
Hello()
-
}
-
}
执行测试性能函数时,需要使用参数-bench,后接性能测试函数名(支持正则表达式)。
如:
-
# go test hello.go hello_test.go -test.bench=BenchmarkHello
-
-
PASS
-
BenchmarkHello hello world
-
hello world
-
hello world
-
hello world
-
...
-
hello world
-
hello world
-
500000 2690 ns/op
-
ok command-line-arguments 1.377s
结果显示,for循环执行了50000次,每次的执行平均时间是2690纳秒。
golang中还提供了pprof来帮助程序员分析程序对cpu、内存、协程等的使用。
根据不同类型的程序可以分3种使用情况:
1. 如果是web服务器的程序,可以直接导入包"net/http/pprof",然后在就能看到分析结果。
2. 如果是一个服务进程(不会退出的程序),可以导入包"net/http/pprof",并用goroutine开启端口监听。
-
go func() {
-
log.Println(http.ListenAndServe("localhost:6060", nil))
-
}()
在就能看到分析结果。
3. 如果是一个一般的应用程序,需要导入包"runtime/pprof",并添加如下代码:
-
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
-
-
func main() {
-
flag.Parse()
-
if *cpuprofile != "" {
-
f, err := os.Create(*cpuprofile)
-
if err != nil {
-
log.Fatal(err)
-
}
-
pprof.StartCPUProfile(f)
-
defer pprof.StopCPUProfile()
-
}
-
...
-
}
例子可参考:
分析pprof文件的命令为:
-
go tool pprof /path/to/binary /path/to/profile
编译生成pprof文件:
-
go build -gcflags='-cpuprofile=mypprof'
分析pprof文件:
-
# go tool pprof profile mypprof
-
Entering interactive mode (type "help" for commands)
-
(pprof) top10
-
30ms of 30ms total ( 100%)
-
Showing top 10 nodes out of 14 (cum >= 10ms)
-
flat flat% sum% cum cum%
-
20ms 66.67% 66.67% 30ms 100% [profile]
-
10ms 33.33% 100% 10ms 33.33% runtime.sysMap
-
0 0% 100% 30ms 100% fmt.(*buffer).WriteByte
-
0 0% 100% 30ms 100% fmt.(*fmt).padString
-
0 0% 100% 10ms 33.33% fmt.(*pp).printReflectValue
-
0 0% 100% 30ms 100% main.main
-
0 0% 100% 10ms 33.33% runtime.(*mcentral).cacheSpan
-
0 0% 100% 10ms 33.33% runtime.(*mcentral).grow
-
0 0% 100% 10ms 33.33% runtime.(*mheap).freeSpan.func1
-
0 0% 100% 10ms 33.33% runtime.call268435456
-
(pprof)
进入交互界面后,可以输入top看到使用cpu最多的函数,也可以输入web生成可视化分析图。
文中代码见:
阅读(4496) | 评论(1) | 转发(0) |