Golang测试包

golang自带了测试包(testing),直接可以进行单元测试、性能分析、输出结果验证等。简单看着官方文档试了试,总结一下:

目录结构和命令

使用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的测试包

package MyTest
import testing

基本的测试函数以Test开头,后面接的字符串,第一个字符必须是数字或者大写,例如:

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提供了自动检查与调用测试函数的机制,测试函数的执行逻辑则需要编写者自行完成。

执行go test 结果为:

Call SetFieldValue()
PASS
ok /go/src/MyTest .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 (.00s)
MyTest_test.go:: Set Field
FAIL
exit status
FAIL _/Users/ronghuihe/Documents/code/golang/my/go/src/MyTest .004s

这并不会中断测试程序,这个函数后面的部分仍然会执行,其他的测试函数也会执行。

性能分析函数

testing包还自带了性能分析功能,可评估代码执行性能。性能分析函数也可以放到前面的xxx_test.go文件内,命名以Benchmark开头,如:

func BenchmarkGetFieldValue(b *testing.B) {
var st MyStruct
SetFieldValue(&st, "hello") for i := ; i < b.N; i++ {
GetFieldValue(&st)
}
}

其中b.N的值在执行过程中会自动调整,使得循环可以执行足够多次,以便得到较为准确的单次结果:
性能分析加-bench参数执行,即go test -bench . (不能漏了最后这个点,它表示执行所有的性能测试函数)

BenchmarkGetFieldValue    SetFieldValue()
SetFieldValue()
SetFieldValue()
SetFieldValue()
SetFieldValue()
SetFieldValue()
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 := ; i < b.N; i++ {
GetFieldValue(&st)
}
}

Golang测试包的更多相关文章

  1. Golang测试技术

    本篇文章内容来源于Golang核心开发组成员Andrew Gerrand在Google I/O 2014的一次主题分享“Testing Techniques”,即介绍使用Golang开发 时会使用到的 ...

  2. Golang Vendor 包管理工具 glide 使用教程

    Glide 是 Golang 的 Vendor 包管理器,方便你管理 vendor 和 verdor 包.类似 Java 的 Maven,PHP 的 Composer. Github:https:// ...

  3. golang测试

    简述 Go语言中自带有一个轻量级的测试框架testing和自带的go test命令来实现单元测试和性能测试. go test [-c] [-i] [build flags] [packages] [f ...

  4. Golang ---testing包

    golang自带了testing测试包,使用该包可以进行自动化的单元测试,输出结果验证,并且可以测试性能. 建议安装gotests插件自动生成测试代码: go get -u -v github.com ...

  5. 如何利用Pre.im分发iOS测试包

    大众创新万众创业,在移动互联网的风口,移动APP开发与测试发展方兴未艾,受到了越来越多的重视.相较 iOS,Android 的开发环境更加开放.Android 开发者要测试应用时,只需发个 APK 安 ...

  6. Golang fmt包使用小技巧

    h1 { margin-top: 0.6cm; margin-bottom: 0.58cm; direction: ltr; color: #000000; line-height: 200%; te ...

  7. Xcode9 打包ipa(导出ipa测试包)时总是意外退出

    今天用xcode9,打包ipa总是意外退出. 正处在测试阶段,所以打的也是测试包 ,路径是:Product -> Archive -> Export -> Save for Ad H ...

  8. Golang Vendor 包机制 及 注意事项

    现在的 Go 版本是 1.8,早在 1.5 时期,就有了 Vendor 包机制,详情可查看博文:“理解 Go 1.5 vendor”. 遇到的问题 个人在使用 Glide 管理 Vendor 包时(附 ...

  9. golang reflect包使用解析

    golang reflect包使用解析 参考 Go反射编码 2个重要的类型 Type Value 其中Type是interface类型,Value是struct类型,意识到这一点很重要 Type和Va ...

随机推荐

  1. 五、curator recipes之选举主节点Leader Latch

    简介 在分布式计算中,主节点选举是为了把某个进程作为主节点来控制其它节点的过程.在选举结束之前,我们不知道哪个节点会成为主节点.curator对于主节点选举有两种实现方式,本文示例演示Latch的实现 ...

  2. 转:zip 和 unzip 的参数说明

    收集的资料: 1. 我想把一个文件abc.txt和一个目录dir1压缩成为yasuo.zip: # zip -r yasuo.zip abc.txt dir1 2.我下载了一个yasuo.zip文件, ...

  3. MySQL的预编译功能

      1.预编译的好处 大家平时都使用过JDBC中的PreparedStatement接口,它有预编译功能.什么是预编译功能呢?它有什么好处呢? 当客户发送一条SQL语句给服务器后,服务器总是需要校验S ...

  4. PHP 经典算法

    <?  //--------------------  // 基本数据结构算法 //--------------------  //二分查找(数组里查找某个元素)  function bin_s ...

  5. python学习之老男孩python全栈第九期_day020知识点总结——序列化模块、模块的导入和使用

    一. 序列化模块 # 序列化 --> 将原本的字典.列表等内容转换成一个字符串的过程就叫做序列化# 反序列化 --> 从字符串转换成数据类型的过程叫做反序列化# 序列 -- 字符串 # 什 ...

  6. Maven学习总结(七):Maven的聚合和继承

    一.聚合 如果我们想一次构建多个项目模块,那我们就需要对多个项目模块进行聚合 1.1.聚合配置代码 1 <modules> 2 <module>模块一</module&g ...

  7. Qt Quick程序的发布

    要将程序发布出去,首先需要使用release方式编译程序,然后将生成的.exe可执行文件和需要的库文件发在一起打包进行发布. 要确定需要哪些动态库文件,可以直接双击.exe文件,提示缺少那个dll文件 ...

  8. Redis的基本操作语句

    注:以下出现的key.value都需要具体 1.String类型的数据存储获取 set key value:设置key的值为value,若存在则覆盖,不存在则自动创建decrby get key:获取 ...

  9. Unity射线

    //射线原点 [SerializField] Transform tr; //射线长度    [SerializField] float dis = 5; //射线停留时间 [SerializFiel ...

  10. 7.Java关键字和保留字

    一.概念 Java关键字(Key Word):  对Java的编译器有特殊的意义,他们用来表示一种数据类型或者表示程序的结构. 保留字(Reserve Word):即它们在Java现有版本中没有特殊含 ...