以前曾经提及过软件测试中的断言,并且对断言的开源库有过简单的介绍。今次是为了为我的开源库 assert 提供的特性进行介绍。
此前也已经介绍过为何在那么多已有的 Golang 断言库之后还要再次制作一个断言库:
- 早期 Go testing 没有抽出 testing.T 和 testing.B 的公共部分,因而已有的断言库往往只能支持 *testing.T 而忽略了 *testing.B 等等
- stretchr 的库有更新、但慢,而且积累了数百个 PR,不太欢迎 PR 的样子
- stretchr 测试库包含太全面了,实际上我的日常只对断言有兴趣,mock 和 suite 并没有必须性。这里的另一个原因也在于 Go testing 现在支持的特性越来越多了。
- 其它的库则是停更好几年了。
- 最后一个原因:我懒得做论文一般地继续查新了。
- Go 自家对于集成测试和 Mock 都有支持了,但唯独断言总是没有,这很奇怪,不可理解,但也不知道什么时候就将会提供内置的断言机制了,然而目前我还是觉得自己的 assert 对于自己的开源代码而言具有实用价值。
hedzr/assert
hedzr/assert
断言库也是仅包含断言工具,是由几个开源断言库的特性综合而来,主要在于将实现代码简化、重写,令断言提示信息更丰富。
引用 hedzr/assert
是通过:
1
import "github.com/hedzr/assert"
以下依次说明这些断言工具的用法:
Equal(t, expect, actual), , NotEqual
相等性断言。
期待 expect 值,而实际得到的是 actual 值,Equal 提供两者之间是否相等的断言。如果失败则测试流程终止。
实际上对其的用法可能是这样的:
1
2
3
4
5
6
expected := []*Person{ {"Alec", 20}, {"Bob", 21}, {"Sally", 22} }
actual := []*Person{ {"Alex", 20}, {"Bob", 22}, {"Sally", 22} }
assert.NotEqual(t, expected, actual)
assert.Equal(t, expected, actual) // 将会失败
}
运行结果类似于:
1
assert_test.go:25 expecting [0xc00000c220 0xc00000c240 0xc00000c260], but got [0xc00000c2a0 0xc00000c2c0 0xc00000c2e0]. DIFF is: []*assert_test....rson{Name: "Alecx", Age: 20}, &a...: "Bob", Age: 212}, &assert_test...lly", Age: 22}}
NotEqual 是不等性断言,只是 Equal 的否定形式。用法类似,不再赘述。
EqualSkip(t, skip, expect, actual), NotEqualSkip
EqualSkip 是 Equal 的等冗长的版本,因为它还需要一个额外的 skip 参数,这个参数用于指明应该忽略的调用栈帧数,从而使得测试的日志输出能够正确地指示源码位置。
NotEqualSkip 是相似的。
查看源码将能够看到 Equal 的实现很简单:
1
2
3
4
// Equal validates that 'actual' is equal to 'expect' and throws an error with line number
func Equal(t testing.TB, expect, actual interface{}) {
EqualSkip(t, 2, expect, actual)
}
EqualFalse(t, actual), EqualTrue(t, actual)
针对布尔量的相等性判定,也提供了更简洁的断言方式:EqualFalse 以及 EqualTrue。因而不再额外详解。
Error(t, err), NoError(t, err)
对于 err 返回值的断言,可以通过 assert.Error 和 assert.NoError 来测试。
1
2
3
4
5
6
7
8
9
func TestErrors(t *testing.T) {
f, err := os.Open("/tmp/not-exist")
assert.Error(t, err) // err 应该是一个 notfound 错误
defer f.Close()
f, err = os.Open("/etc/passwd")
assert.NoError(t, err) // err 应该为 nil
defer f.Close()
}
Nil(t, value), NotNil(t, val)
对于指针或者空数组,或者未初始化的 channel 等等,可以通过 Nil 和 NotNil 来测试。
1
2
3
4
5
6
7
func TestNilObjects(t *testing.T) {
var ch chan struct{}
assert.Nil(t, ch)
ch = make(chan struct{})
assert.NotNil(t, ch)
close(ch)
}
Match(t, value, regex), NotMatch
对于字符串类型的变量,除了通过相等性断言来测试之外,也可以采用正则式来进行测试和判定:
1
2
3
4
func TestStrings(t *testing.T){
var s = "365 days"
assert.Match(t, s, `\d[ ]*days`)
}
PanicMatches(t, fn, matches)
而对于 panic 问题,PanicMatches 可以对 fn 发生的 panics 具体内容进行测试:
1
2
3
4
5
6
7
8
func TestPanics(t *testing.T) {
fn := func() {
panic("omg omg omg!")
}
assert.PanicMatches(t, func() { fn() }, "omg omg omg!")
assert.PanicMatches(t, func() { panic("omg omg omg!") }, "omg omg omg!")
}
其它
DiffValues(a, b)
DiffValues 可以用于比较 a 和 b 的不同之处,并以终端彩色输出的形式表现出来,因此你可以通过 print DiffValues(a, b) 的方式来获得一个彩色的终端输出,其式样类似于:
DiffValuesDefault(a, b)
DiffValuesDefault 与 DiffValues 的区别在于, DiffValues 不关心那些为零值的字段的可能的不同之处,而 DiffValuesDefault 则不会略过这些字段。
🔚
留下评论