Chinaunix首页 | 论坛 | 博客
  • 博客访问: 189027
  • 博文数量: 21
  • 博客积分: 250
  • 博客等级: 二等列兵
  • 技术积分: 470
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-06 23:10
个人简介

程序猿

文章分类

全部博文(21)

文章存档

2016年(17)

2014年(3)

2013年(1)

分类: LINUX

2016-05-29 16:08:44

golang从语言层面支持了单元测试。
只要把代码文件和测试函数按照指定的规则命名,就能实现自动化的测试。
测试可以分为功能测试和性能测试,下面分别来说明。

功能测试

golang规定所有测试代码必须放在以"_test.go"结尾的文件中。
测试函数必须以Test开头,紧跟的字符串首字符必须是大写字母或数字,参数为testing包的T类型指针。
  1. func TestXxx(*testing.T)
我们可以写一个Hello()函数并使用TestHello()函数来测试。
Hello()定义在hello.go中:
  1. package hello
  2. import (
  3.   "fmt"
  4. )
  5. func Hello() {
  6.   fmt.Printf("hello world\n")
  7. }
TestHello()定义在hello_test.go中,该文件和hello.go放在相同目录下:
  1. package hello
  2. import (
  3.   "testing"
  4. )
  5. func TestHello(t *testing.T) {
  6.   Hello()
  7. }
执行go test命令,测试工具会自动完成代码编译和运行。打印结果:
  1. # go test
  2. ok command-line-arguments 0.003s

下面再来看一个更实际的例子:
定义一个Add()函数,使用TestAdd()来测试Add()函数的功能。
可以使用testing包的T类型方法来帮助我们显示测试结果。

# cat add_test.go
  1. package hello
  2. import "testing"
  3. func TestAdd1(t *testing.T) {
  4.   if Add(2, 4) == 6 {
  5.     t.Log("test add1 passed")
  6.   } else {
  7.     t.Error("test add1 failed")
  8.   }
  9. }

运行go test会运行目录下所有的测试函数,也可以指定一个测试文件:
  1. go test add_test.go
或是指定测试的函数:
  1. go test -run="TestAdd1"
输出结果:
  1. # go test -run="TestAdd1"
  2. PASS
  3. ok github.com/vv1133/golang_example/test 0.005s
我们发现,用t.Log()打印的内容并没有显示出来,这是因为默认情况下Log级别的打印不会被输出到控制台,可以用-v参数来显示更详细的测试信息。
  1. # go test -run="TestAdd1" -v
  2. === RUN TestAdd1
  3. --- PASS: TestAdd1 (0.00s)
  4. add_test.go:7: test add1 passed
  5. PASS
  6. ok github.com/vv1133/golang_example/test 0.003s


另一个测试的方法是使用Example前缀。
go测试工具会自动捕获这些函数的标准输出,并和注释中以“Output:”开头的内容比较,如果相同则测试通过。
  1. func ExampleHello_test1() {
  2.   Hello()
  3.   // Output: hello world
  4. }

  1. # go test -run="ExampleHello_test1" -v
  2. === RUN ExampleHello_test1
  3. --- PASS: ExampleHello_test1 (0.00s)
  4. PASS
  5. ok github.com/vv1133/golang_example/test 0.004s

性能测试

性能测试函数需要以Benchmark作为函数名前缀,后接的字符串首字符必须是大写字母或数字。参数是testing包中的类型B。
  1. func BenchmarkHello(b *testing.B) {
  2.   for i := 0; i < b.N; i++ {
  3.     Hello()
  4.   }
  5. }
执行测试性能函数时,需要使用参数-bench,后接性能测试函数名(支持正则表达式)。
如:
  1. # go test hello.go hello_test.go -test.bench=BenchmarkHello
  2. PASS
  3. BenchmarkHello hello world
  4. hello world
  5. hello world
  6. hello world
  7. ...
  8. hello world
  9. hello world
  10. 500000 2690 ns/op
  11. ok command-line-arguments 1.377s
结果显示,for循环执行了50000次,每次的执行平均时间是2690纳秒。


golang中还提供了pprof来帮助程序员分析程序对cpu、内存、协程等的使用。
根据不同类型的程序可以分3种使用情况:
1. 如果是web服务器的程序,可以直接导入包"net/http/pprof",然后在http://localhost:port/debug/pprof/就能看到分析结果。

2. 如果是一个服务进程(不会退出的程序),可以导入包"net/http/pprof",并用goroutine开启端口监听。
  1. go func() {
  2.    log.Println(http.ListenAndServe("localhost:6060", nil))
  3. }()
在http://localhost:port/debug/pprof/就能看到分析结果。

3. 如果是一个一般的应用程序,需要导入包"runtime/pprof",并添加如下代码:
  1. var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
  2. func main() {
  3.    flag.Parse()
  4.    if *cpuprofile != "" {
  5.      f, err := os.Create(*cpuprofile)
  6.      if err != nil {
  7.        log.Fatal(err)
  8.      }
  9.      pprof.StartCPUProfile(f)
  10.      defer pprof.StopCPUProfile()
  11.    }
  12.    ...
  13. }

例子可参考:
https://github.com/vv1133/golang_example/blob/master/profile/main.go

分析pprof文件的命令为:
  1. go tool pprof /path/to/binary /path/to/profile

编译生成pprof文件:
  1. go build -gcflags='-cpuprofile=mypprof'
分析pprof文件:
  1. # go tool pprof profile mypprof
  2. Entering interactive mode (type "help" for commands)
  3. (pprof) top10
  4. 30ms of 30ms total ( 100%)
  5. Showing top 10 nodes out of 14 (cum >= 10ms)
  6. flat flat% sum% cum cum%
  7. 20ms 66.67% 66.67% 30ms 100% [profile]
  8. 10ms 33.33% 100% 10ms 33.33% runtime.sysMap
  9. 0 0% 100% 30ms 100% fmt.(*buffer).WriteByte
  10. 0 0% 100% 30ms 100% fmt.(*fmt).padString
  11. 0 0% 100% 10ms 33.33% fmt.(*pp).printReflectValue
  12. 0 0% 100% 30ms 100% main.main
  13. 0 0% 100% 10ms 33.33% runtime.(*mcentral).cacheSpan
  14. 0 0% 100% 10ms 33.33% runtime.(*mcentral).grow
  15. 0 0% 100% 10ms 33.33% runtime.(*mheap).freeSpan.func1
  16. 0 0% 100% 10ms 33.33% runtime.call268435456
  17. (pprof)
进入交互界面后,可以输入top看到使用cpu最多的函数,也可以输入web生成可视化分析图。


文中代码见:
https://github.com/vv1133/golang_example/tree/master/test/
https://github.com/vv1133/golang_example/blob/master/profile/


阅读(2199) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

不懂IT2016-06-05 23:31:53

排版一直这么简洁又明了,真个是个好老师,我看了七八篇居然一个错别字都没有!!!

真的就像写教材的人,一句废话都没有,每一句都是客观又实在。

这么热情贡献经验,真的是个好IT人。

好可惜我听不懂你说的是什么

但你写的我都愿意看,努力去想明白到底是个啥

评论热议
请登录后评论。

登录 注册