golang进阶(七)——go语言的几种测试方法
来源:互联网 发布:胸大 知乎 编辑:程序博客网 时间:2024/06/06 05:20
前言
用了go的测试框架,再想下junit的,虽然已经Junit5,那丑陋程度还是依然。
java出来的时候,还没有很多软件工程的概念,语言先出来了,因此需要通过不同的插件慢慢补。
go就很幸运,出来的时候很多软件工程的概念已经基本定了下来,可以加到语言特性之中,go的测试就简便很多,不愧是为工程而生的语言
需要测试的程序
我们需要测试的程序文件叫做utils.go
,里面有个字符串反转的方法Reverse
,代码相对简单,这里就不赘述了
func Reverse(s string) string { r := []rune(s) for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { r[i], r[j] = r[j], r[i] } return string(r)}
单元测试
go的testing包可以基于包进测试,意思是执行go test
默认单位是包范围,go test
可以自动执行当前包下面的所有func TestXxx(*testing.T)
格式的测试方法,Xxx可以是任意字母,但最好和你需要测试方法一一对应。
新建一个测试的文件,要以_test.go
作为文件名的结尾,最好和需要测试的文件一一对应,可以一目了然,这些test文件在程序构建的时候是不会一起打包到最终执行文件或者库中的。
我们新建utlis_test.go
文件:
func TestReverse(t *testing.T) { if testing.Short() { t.Skip("skipping test in short mode.") } cases := []struct { in, want string }{ {"Hello, world", "dlrow ,olleH"}, {"Hello, 世界", "界世 ,olleH"}, {"", ""}, } for _, c := range cases { got := Reverse(c.in) if got != c.want { t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want) } }}
第一个if表示如果有-short
参数,将会跳过这个测试,后面的代码相对就很容易看懂了,判断下输出输入是否一致,以上测试方法通过go test
命令可以直接运行
示例验证
还有一种可以当做测试的方法就是使用示例验证程序,做一个示例在go语言也非常简单,告别写点示例程序就得写好多main方法的时代吧,格式要以Example开头,执行go test
的时候会自动执行这些示例,要注意一点的是,Example之后需要跟已定义的变量,否则vet
会报错。
还有一点注意的是,会自动trim,而忽略前后的空格比较。
func ExampleReverse() { fmt.Println(Reverse("Hello, 世界")) // Output: 界世 ,olleH}
可以验证输出是否与想要的一致,还有一些情况下,比如多线程的情况下,输出顺序是随机的,这点go也考虑到了,
func ExampleReverse() { fmt.Println(Reverse("Hello, world")) fmt.Println(Reverse("Hello, 世界")) // Unordered Output: 界世 ,olleH // dlrow ,olleH // AA}
用Unordered Output
来表示无序输出
基准测试
基准测试以Benchmark
为前缀,必须要执行b.N
次,这样的测试才有对照性,b.N
的值是系统根据实际情况去调整的,从而保证测试的稳定性。
b.ResetTimer()
之前的处理不会放到执行时间里,也不会输出到报告中,所以可以在之前做一些不计划作为测试报告的操作
基准测试并不会默认执行,他需要增加-bench
参数,例如go test -bench .
func BenchmarkReverse(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { Reverse("s string") }}
基准测试也可以开启并行测试,需要执行b.RunParallel(func(pb *testing.PB)
方法,默认会以逻辑CPU个数来进行并行测试。
个人意见只写并行测试就ok了,如果想非并行可以指定cpu数量为1,例如go test -bench . -cpu 1
func BenchmarkReverseParallel(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { Reverse("s string") } })}
子测试和子基准测试
还可以通过T
和B
的Run方法开启子测试和子基准测试,主要是可以共享公共的设置和资源清除的管理
每个子测试都有一个唯一的名字,以父测试用/
隔开来唯一表示,运行的时候使用-run regexp
指定测试和-bench regexp
来指定基准测试,.
表示所有。
还有一个特点就是所有子测试完成,父测试才算完成,而且所有测试都是并行的,这样可以把一些需要同步完成的操作来进行分组测试。
func TestTeardownParallel(t *testing.T) { // This Run will not return until the parallel tests finish. t.Run("group", func(t *testing.T) { t.Run("Test1", parallelTest1) t.Run("Test2", parallelTest2) t.Run("Test3", parallelTest3) }) // <tear-down code>}
Main测试
还有一个可以做一些初始化的地方就是main测试了,代码也相对简单。
要注意的testmain是在主协程运行的,m.Run()
开始运行时,其他测试才会执行
func TestMain(m *testing.M) { fmt.Println("init") os.Exit(m.Run())}
附带揭露一下滴滴的jsoniter
为了kpi连基准测试都要作弊吗?
可见自己会写基准测试很重要,不会被人忽悠瘸了
来看我的基准测试
type ColorGroup struct { ID int Name string Colors []string}var group = ColorGroup{ ID: 1, Name: "Reds", Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},}func BenchmarkStdJson(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { b, err := json.Marshal(group) if err != nil { fmt.Println(b) } } })}func BenchmarkIterJson(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { b, err := jsoniter.Marshal(group) if err != nil { fmt.Println(b) } } })}
测试结果:
- golang进阶(七)——go语言的几种测试方法
- golang进阶(八)——隐藏技能go:linkname
- Go实战--golang中读写文件的几种方式
- Go实战--golang中读写文件的几种方式
- 38.笔记go语言——进阶
- golang substring方法的几种实现
- go语言学习-golang的基本数据类型
- go语言学习-golang的基本数据类型
- astilectron之Go语言golang的图形界面
- golang: Go语言:简介
- go/golang main() init()方法的调用
- Golang Go语言结构体中匿名字段暴露方法的优先级
- go语言之斐波那契数列的几种实现方法
- go学习(十一)——Go 语言自动化测试
- golang中获取字符串长度的几种方法
- go语言 Golang官网被墙解决办法
- 【GOLANG】Go语言学习-logger
- GO语言(golang)官方网站!
- H5混合开发二维码扫描以及调用本地摄像头
- java编程中spring boot 使用spring.profiles.active来分区配置
- 使用 GROUP BY 的 WITH ROLLUP
- Java中关于定时自动任务的实现
- RTLAB异步通信---客户端代码
- golang进阶(七)——go语言的几种测试方法
- unity开发: socket网络连接
- CentOS 6.6源码安装Python 2.7
- 快速上手友盟推送前后端
- 会声会影的多点运动追踪你会用么
- 实在没想到系列——HashMap实现底层细节之keySet,values,entrySet的一个底层实现细节
- android StrictMode(严苛模式)详解
- 9.Python的基本运算和表达式(上)
- log4j的详细使用