前言
Welcome to GoConvey, a yummy testing tool for gophers.
go convey是一个支持golang的单元测试框架
go convey能够自动监控文件修改并启动测试,并可以将测试结果实时输出到Web界面
go convey提供了丰富的断言简化测试用例的编写
特点:
- 直接与 go test 集成
- 巨大的回归测试套件
- 可读性强的色彩控制台输出
- 完全自动化的 Web UI:桌面提醒(可选);半自动化书写测试用例:http://localhost:8080/composer.html;查看测试覆盖率:http://localhost:8080/reports/
- 自动检测代码变动并编译测试
- 临时屏蔽某个包的编译测试
详见官方文档:https://github.com/smartystreets/goconvey
安装
go get github.com/smartystreets/goconvey
在想要检测的目录下执行goconvey 开启web ui
基本使用
func TestIntegerStuff(t *testing.T) {
Convey("Given some integer with a starting value", t, func() {
x := 1
Convey("When the integer is incremented", func() {
x++
Convey("The value should be greater by one", func() {
So(x, ShouldEqual, 2)
})
})
})
}
注意:t *testing.T 只在最高级别的Convey中传递既可;Convey 语句同样可以无限嵌套,以体现各个测试用例之间的关系,
测试代码
测试使用方法:
func Splittostring(s, sep string) (res []string) {
res = make([]string, 0, strings.Count(s, sep)+1)
i := strings.Index(s, sep)
for i >= 0 {
res = append(res, s[:i])
s = s[i+len(sep):]
i = strings.Index(s, sep)
}
res = append(res, s)
return
}
单个测试
func TestSplittostring2convey(t *testing.T) {
Convey("testSplittostring", t, func() {
//可以使用标准断言,也是可以自己写断言方法
shouldFunc := func(actual interface{}, expected ...interface{}) string {
if !reflect.DeepEqual(actual, expected[0]) { // 因为slice不能比较直接,借助反射包中的方法比较
return fmt.Sprintf("excepted:%v, got:%v", expected, actual) // 测试失败输出错误提示
}
return ""
}
Convey("test a:b:c |:", func() {
So(Splittostring("a:b:c", ":"), shouldFunc, []string{"a", "b", "c"})
})
})
}
注意:go convey 提供了很多标准断言;但是也提供了,自定义断言的方法:
详见:https://github.com/smartystreets/goconvey/wiki/Assertions
自定义断言方法:
func should<do-something>(actual interface{}, expected ...interface{}) string {
if <some-important-condition-is-met(actual, expected)> {
return "" // empty string means the assertion passed
}
return "<some descriptive message detailing why the assertion failed...>"
}
子测试
//子测试
func TestSplittostringWithSubTest2convey(t *testing.T) {
Convey("testSplittostring with subtest", t, func() {
shouldFunc := func(actual interface{}, expected ...interface{}) string {
g := actual.([]string)
w := expected[0].([]string)
if !reflect.DeepEqual(g, w) { // 因为slice不能比较直接,借助反射包中的方法比较
return fmt.Sprintf("excepted:%v, got:%v", expected, actual) // 测试失败输出错误提示
}
return ""
}
Convey("test a:b:c |:", func() {
So(Splittostring("a:b:c", ":"), shouldFunc, []string{"a", "b", "c"})
})
Convey("test adfgadsf | d", func() {
So(Splittostring("adfgadsf", "d"), shouldFunc, []string{"a", "fga", "sf"})
})
Convey("test avddfddfddf | fd", func() {
So(Splittostring("avddfddfddf", "fd"), shouldFunc, []string{"avdd", "d", "df"})
})
})
}
注意:
- 分割多个测试用例到多个组别里面,每个组别有一个或多个测试用例;使得测试显示信息的时候可以直观地看出测试用例的结构
- 前面的测试用例如果是错的,测试函数还是会继续执行,直到将所有的测试用例都执行完。等同于使用t.Run()执行子测试;
- 如果我们的函数,有一些功能还没实现,对于某些测试用例来说不可用,那该怎么办呢?GoConvey提供了两种方法可以忽略测试用例,一种是SkipConvey,用于直接忽略整个Convey。一种是SkipSo,用于忽略某个断言。SkipSo更适用于Convey嵌套时,忽略某个大Convey下的小Convey对应的So
- 当测试函数还没有写完成的时候,也可以通过Convey("", t,nil)的方式来忽略测试
命令行测试查看
和原生测试命令等同
go test -v
#查看详情
当存在SkipConvey或SkipSo时,测试日志中会显式打上"skipped"形式的标记:
当测试代码中存在SkipConvey时,相应闭包函数中不管是否为SkipSo,都将被忽略,测试日志中对应的符号仅为一个"⚠"
当测试代码Convey语句中存在SkipSo时,测试日志中每个So对应一个"✔"或"✘",每个SkipSo对应一个"⚠",按实际顺序排列
不管存在SkipConvey还是SkipSo时,测试日志中都有字符串"{n} total assertions (one or more sections skipped)",其中{n}表示测试中实际已运行的断言语句数