GoConvey是一款针对Golang的测试框架,能够管理和运行测试用例,同时提供了丰富的断言函数,并支持多种Web界面特性。
官方地址:
https://github.com/smartystreets/goconvey
安装:go get github.com/smartystreets/goconvey
git
GoConvey支持 go test,可直接在终端窗口和浏览器上使用。GoConvey特色以下:
A、直接集成go test
B、巨大的回归测试套件
C、可读性强的色彩控制台输出
D、彻底自动化的Web UI
E、测试代码生成器github
官方文档:
https://github.com/smartystreets/goconvey/wiki
GoConvey自带大量的标准断言函数,能够经过So()使用。
(1)通用相等比较
So(thing1, ShouldEqual, thing2)
So(thing1, ShouldNotEqual, thing2)
So(thing1, ShouldResemble, thing2)
用于数组、切片、map和结构体的深度比较
So(thing1, ShouldNotResemble, thing2)
So(thing1, ShouldPointTo, thing2)
So(thing1, ShouldNotPointTo, thing2)
So(thing1, ShouldBeNil)
So(thing1, ShouldNotBeNil)
So(thing1, ShouldBeTrue)
So(thing1, ShouldBeFalse)
So(thing1, ShouldBeZeroValue)
(2)数值比较
So(1, ShouldBeGreaterThan, 0)
So(1, ShouldBeGreaterThanOrEqualTo, 0)
So(1, ShouldBeLessThan, 2)
So(1, ShouldBeLessThanOrEqualTo, 2)
So(1.1, ShouldBeBetween, .8, 1.2)
So(1.1, ShouldNotBeBetween, 2, 3)
So(1.1, ShouldBeBetweenOrEqual, .9, 1.1)
So(1.1, ShouldNotBeBetweenOrEqual, 1000, 2000)
So(1.0, ShouldAlmostEqual, 0.99999999, .0001)
带容差比较,默认容差为0.0000000001
So(1.0, ShouldNotAlmostEqual, 0.9, .0001)
(3)数据集合比较
So([]int{2, 4, 6}, ShouldContain, 4)
So([]int{2, 4, 6}, ShouldNotContain, 5)
So(4, ShouldBeIn, ...[]int{2, 4, 6})
So(4, ShouldNotBeIn, ...[]int{1, 3, 5})
So([]int{}, ShouldBeEmpty)
So([]int{1}, ShouldNotBeEmpty)
So(map[string]string{"a": "b"}, ShouldContainKey, "a")
So(map[string]string{"a": "b"}, ShouldNotContainKey, "b")
So(map[string]string{"a": "b"}, ShouldNotBeEmpty)
So(map[string]string{}, ShouldBeEmpty)
So(map[string]string{"a": "b"}, ShouldHaveLength, 1)
支持map、切片、通道、字符串
(4)字符串比较
So("asdf", ShouldStartWith, "as")
So("asdf", ShouldNotStartWith, "df")
So("asdf", ShouldEndWith, "df")
So("asdf", ShouldNotEndWith, "df")
So("asdf", ShouldContainSubstring, "sd")
So("asdf", ShouldNotContainSubstring, "er")
So("adsf", ShouldBeBlank)
So("asdf", ShouldNotBeBlank)
(5)异常比较
So(func(), ShouldPanic)
So(func(), ShouldNotPanic)
So(func(), ShouldPanicWith, "") // or errors.New("something")
So(func(), ShouldNotPanicWith, "") // or errors.New("something")
(6)类型检查
So(1, ShouldHaveSameTypeAs, 0)
So(1, ShouldNotHaveSameTypeAs, "asdf")
(7)时间比较
So(time.Now(), ShouldHappenBefore, time.Now())
So(time.Now(), ShouldHappenOnOrBefore, time.Now())
So(time.Now(), ShouldHappenAfter, time.Now())
So(time.Now(), ShouldHappenOnOrAfter, time.Now())
So(time.Now(), ShouldHappenBetween, time.Now(), time.Now())
So(time.Now(), ShouldHappenOnOrBetween, time.Now(), time.Now())
So(time.Now(), ShouldNotHappenOnOrBetween, time.Now(), time.Now())
So(time.Now(), ShouldHappenWithin, duration, time.Now())
So(time.Now(), ShouldNotHappenWithin, duration, time.Now())数组
官方推荐使用导入GoConvey的辅助包以减小冗余的代码:. "github.com/smartystreets/goconvey/convey"
GoConvey包导入在工程代码中以下:浏览器
import ( "testing" . "github.com/smartystreets/goconvey/convey" )
每一个单元测试的名称需以 Test 开头,并须要接收一个类型为 *testing.T
的参数。
每一个测试用例须要使用Convey函数包裹起来,第一个参数为string类型的测试用例描述;第二个参数通常为 *testing.T
;第三个参数为不接收任何参数也不返回任何值的函数(一般以闭包的形式书写)。
Convey语句能够无限嵌套,以体现各个测试用例之间的关系,只有最外层的 Convey 须要传入*testing.T
类型变量,内层嵌套的Convey不须要传入。闭包
func TestAdd(t *testing.T) { Convey("将两数相加", t, func() { So(Add(1, 2), ShouldEqual, 3) }) }
GoConvey提供了Convey/So的Skip宏,用于想忽略某些断言操做但不想删除或注释的场景。
SkipConvey:代表相应的闭包函数将不被执行。
SkipSo:代表相应的断言将不被执行。
当存在SkipConvey或SkipSo时,测试日志中会显式打上"skipped"形式的标记:
当测试代码中存在SkipConvey时,相应闭包函数中无论是否为SkipSo,都将被忽略,测试日志中对应的符号仅为一个"⚠"
当测试代码Convey语句中存在SkipSo时,测试日志中每一个So对应一个"✔"或"✘",每一个SkipSo对应一个"⚠",按实际顺序排列
无论存在SkipConvey仍是SkipSo时,测试日志中都有字符串"{n} total assertions (one or more sections skipped)",其中{n}表示测试中实际已运行的断言语句数。app
Operator.go文件:框架
package Operator import ( "errors" ) func Add(a, b int) int { return a + b } func Subtract(a, b int) int { return a - b } func Multiply(a, b int) int { return a * b } func Division(a, b int) (int, error) { if b == 0 { return 0, errors.New("Divisor is 0") } return a / b, nil }
Operator_test.go文件:ide
package Operator import ( "testing" . "github.com/smartystreets/goconvey/convey" ) func TestAdd(t *testing.T) { Convey("将两数相加", t, func() { So(Add(1, 2), ShouldEqual, 3) }) } func TestSubtract(t *testing.T) { Convey("将两数相减", t, func() { So(Subtract(1, 2), ShouldEqual, -1) }) } func TestMultiply(t *testing.T) { Convey("将两数相乘", t, func() { So(Multiply(3, 2), ShouldEqual, 6) }) } func TestDivision(t *testing.T) { Convey("将两数相除", t, func() { Convey("除以非 0 数", func() { num, err := Division(10, 2) So(err, ShouldBeNil) So(num, ShouldEqual, 5) }) Convey("除以 0", func() { _, err := Division(10, 0) So(err, ShouldNotBeNil) }) }) }
So的函数原型以下:函数
func So(actual interface{}, assert assertion, expected ...interface{}) type assertion func(actual interface{}, expected ...interface{}) string
当assertion的返回值为""时表示断言成功,不然表示失败,GoConvey框架中的相关代码为:单元测试
const ( success = "" needExactValues = "This assertion requires exactly %d comparison values (you provided %d)." needNonEmptyCollection = "This assertion requires at least 1 comparison value (you provided 0)." )
定制断言函数以下:
func ShouldSummerBeComming(actual interface{}, expected ...interface{}) string { if actual == "summer" && expected[0] == "comming" { return "" } else { return "summer is not comming!" } }
单元测试以下:
func TestSummer(t *testing.T) { Convey("TestSummer", t, func() { So("summer", ShouldSummerBeComming, "comming") So("winter", ShouldSummerBeComming, "comming") }) }
根据ShouldSummerBeComming的实现,闭包中第一个So将断言成功,第二个So将断言失败。
GoConvey兼容Go原生的单元测试,能够直接使用Go命令来执行测试。
在测试代码目录下运行go test命令: go test -v
测试执行结果以下:
=== RUN TestAdd 将两数相加 ✔ 1 total assertion --- PASS: TestAdd (0.00s) === RUN TestSubtract 将两数相减 ✔ 2 total assertions --- PASS: TestSubtract (0.00s) === RUN TestMultiply 将两数相乘 ✔ 3 total assertions --- PASS: TestMultiply (0.00s) === RUN TestDivision 将两数相除 除以非 0 数 ✔✔ 除以 0 ✔ 6 total assertions --- PASS: TestDivision (0.00s) PASS ok GoExample/GoConvey 0.002s
查看goconvey用法goconvey -h
-cover:开启覆盖率统计功能
-depth int:扫描目录的深度,-1:扫描无穷深度,0:扫描当前目录
-excludedDirs string:将某些目录排除在扫描外,多个目录使用逗号分割
-host string:指定开启HTTP服务的主机
-launchBrowser:触发自动开启浏览器,默认为true
-port int:指定HTTP服务的端口
-workDir string:指定工做目录,默认为当前目录
在测试用例源码目录下运行goconvey:goconvey -port 8081
在浏览器打开:
http://localhost:8081
结果以下: