GoConvey测试框架


针对Golang的测试框架
管理和运行测试用例  提供 丰富的断言函数 支持 Web 界面
GoConvey 网站
//smartystreets.github.io/goconvey/
在终端窗口和浏览器上使用
GoConvey
直接与 go test 集成
巨大的回归测试套件
可读性强的色彩控制台输出
完全自动化的 Web UI
测试代码生成器
桌面提醒(可选)
自动在终端中运行自动测试脚本
可立即在 Sublime Text 中打开测试问题对应的代码行 (some assembly required)
安装
$ cd <project path>
$ go get github.com/smartystreets/goconvey
$ $GOPATH/bin/goconvey
打开浏览器 http://localhost:8080
如果存在测试代码 将会自动运行并展示在浏览器中
编写goconvey测试用例
Convey("Comparing two variables", t, func() {
    myVar := "Hello, world!"
    Convey(`"Asdf" should NOT equal "qwerty"`, func() {
        So("Asdf", ShouldNotEqual, "qwerty")
    })
 
    Convey("myVar should not be nil", func() {
        So(myVar, ShouldNotBeNil)
    })
})
如果有未完成的测试或场景 可以设置成nil或者skip
Convey("This isn't yet implemented", nil)
标准断言(Assertions):GoConvey自带了很多的标准断言 用So()来使用
General Equality
So(thing1, ShouldEqual, thing2)
So(thing1, ShouldNotEqual, thing2)
So(thing1, ShouldResemble, thing2)        // a deep equals for arrays, slices, maps, and structs
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)
Numeric Quantity comparison
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)   // tolerance is optional; default 0.0000000001
So(1.0, ShouldNotAlmostEqual, 0.9, .0001)
Collections
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) // supports map, slice, chan, and string
Strings
So("asdf", ShouldStartWith, "as")
So("asdf", ShouldNotStartWith, "df")
So("asdf", ShouldEndWith, "df")
So("asdf", ShouldNotEndWith, "df")
So("asdf", ShouldContainSubstring, "sd")        // optional 'expected occurences' arguments?
So("asdf", ShouldNotContainSubstring, "er")
So("adsf", ShouldBeBlank)
So("asdf", ShouldNotBeBlank)
panic
So(func(), ShouldPanic)
So(func(), ShouldNotPanic)
So(func(), ShouldPanicWith, "")        // or errors.New("something")
So(func(), ShouldNotPanicWith, "")    // or errors.New("something")
Type checking
So(1, ShouldHaveSameTypeAs, 0)
So(1, ShouldNotHaveSameTypeAs, "asdf")
time.Time (and time.Duration)
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())
自定义断言
有些特殊场景标准断言不能满足
需要使用自定义断言
只是实现一个函数具有以下签名(替换括号部分和字符串值):
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 shouldScareGophersMoreThan(actual interface{}, expected ...interface{}) string {
    if actual == "BOO!" && expected[0] == "boo" {
        return ""
    }
    return "Ha! You'll have to get a lot friendlier with the capslock if you want to scare a gopher!"
}
用例中调用So():
Convey("All caps always makes text more meaningful", func() {
    So("BOO!", shouldScareGophersMoreThan, "boo")
})
执行测试
go test -gcflags "all=-N -l" -v
go建议使用最新版本
用例执行顺序
看下面例子
Convey A
    So 1
    Convey B
        So 2
    Convey C
        So 3
可能你一开始觉得会是A1B2C3这样顺序执行的 但是实际上是按照A1B2然后A1C3这样的顺序执行的
这种树形结构的测试行为消除了很多重复的设置代码
同时允许孤立的测试
一个更加复杂的例子:
Convey A
    So 1
    Convey B
        So 2
        Convey Q
            So 9
    Convey C
        So 3
执行顺序为:A1B2Q9A1C3
陷阱
Convey("Setup", func() {
    foo := &Bar{}
    Convey("This creates a new variable foo in this scope", func() {
        foo := &Bar{}
    }
    Convey("This assigns a new value to the previous declared foo", func() {
        foo = &Bar{}
    }
}
每次调用Convey()都会创建一个新的scope,你应该使用Foo = &Bar{}为之前声明的变量赋值
使用foo := &Bar{}在当前scope中创建一个新变量
Reset
有时候需要在跑完一个用例后 清除converys中的一些预配置 这时应该使用Reset()来清除 如下例子:
Convey("Top-level", t, func() {
    // setup (run before each `Convey` at this scope):
    db.Open()
    db.Initialize()
    Convey("Test a query", func() {
        db.Query()// TODO: assertions here
    })
    Convey("Test inserts", func() {
        db.Insert()
        // TODO: assertions here
    })
    Reset(func() {
        // This reset is run after each `Convey` at the same scope.
        db.Close()
    })
})
Skip:有些场景需要忽略或都跳过整个scope或者一个So断言
在GoConvey中很容易实现
跳过整个Convey
SkipConvey("Important stuff", func() {//这个方法不会执行
    Convey("More important stuff", func() {
        So("asdf", ShouldEqual, "asdf")
    })
})
未完成的Convey
Convey("Some stuff", func() {
    // This will show up as 'skipped' in the report
    Convey("Should go boink", nil)
 
}
跳过So断言:类似SkipConvey
Convey("1 Should Equal 2", func() {    
    // This assertion will not be executed and will show up as 'skipped' in the report
    SkipSo(1, ShouldEqual, 2)
 
})
自动测试:GoConvey有两个运行自动测试的方式:在terminal和browser中
在terminal中
下载https://gist.github.com/mdwhatcott/9107649
cd <folder_with_tests_or_packages>
auto-run.py -v
在browser中:使用goconvey server
Web UI:一个强大的 简洁的在浏览器中展示go test结果的工具
特点
自定义监控目录
当.go文件修改后自动更新Web UI
测试代码生成
浏览器通知
失败的用例使用带颜色的输出
嵌套显示GoConvey用例以方便阅读
支持原生的go tests
响应式页面设计
高亮显示panics,build失败,失败用例