et
全名是EasyTest
,它是一个有着丰富断言函数的,可扩展的单元测试辅助库.
et
无额外的包依赖,您可以直接下载代码到本地,也可以通过下面的命令获取:
$ go get -u github.com/tinyhubs/et
package examples
import (
"testing"
"github.com/tinyhubs/et/assert"
)
func TestAssert_Equal(t *testing.T) {
assert.Equal(t, "123", "456")
}
func TestAssert_Equali(t *testing.T) {
assert.Equali(t, "Expect-the-values-is-equal", "123", "456")
}
上面的例子的输出如下,每个失败的用例的第二行堆栈信息就是断言出错的的assert或者是expect的代码的位置.
et-core.go:16:
/Users/llj/mygithub/src/github.com/tinyhubs/et/examples/example1_test.go:9
Expect:123, Actual:456
et-core.go:18:
/Users/llj/mygithub/src/github.com/tinyhubs/et/examples/example1_test.go:13
Expect-the-values-is-equal
Expect:123, Actual:456
- 相等检测:
assert.Equal
assert.Equal(t, "123", "456")
- 布尔检测:
assert.True
assert.True(t, "123" == "456")
- 检测是否会抛异常:
assert.Panic
assert.Panic(t, func() { /* Do nothing. */ })
- 检测是否匹配正则表达式:
assert.Match
assert.Match(t, `^[a-zA-Z0-9-_]+@timo\.com$`, "[email protected]")
- 检测是否为nil:
assert.Nil
assert.Nil(t, bytes.NewBufferString(""))
et
提供了assert和expect两套接口,所有在assert中存在的函数,except中也会存在.
比如,assert里面有assert.Equal
,那么也会存在except.Equal
.
assert系接口和expect系的接口也可以组合使用,以便实现更丰富的功能.
assert和expect的区别就是assert会立即中断当前用例的执行,而expect会一直执行下去直到用例执行完毕:
package examples
import (
"testing"
"github.com/tinyhubs/et/expect"
"github.com/tinyhubs/et/assert"
)
func Test_2_Expect_Equal(t *testing.T) {
expect.Equal(t, "123", "456")
expect.Equal(t, 333, 7788)
expect.Equal(t, "sina", "sina")
} // stoped here
func Test_2_Assert_Equal(t *testing.T) {
assert.Equal(t, "123", "456") // stoped here
assert.Equal(t, 333, 7788)
assert.Equal(t, "sina", "sina")
}
这个两个用例的输出结果如下:
et-core.go:28:
/Users/llj/mygithub/src/github.com/tinyhubs/et/examples/example2_test.go:10
Expect:123, Actual:456
et-core.go:28:
/Users/llj/mygithub/src/github.com/tinyhubs/et/examples/example2_test.go:11
Expect:333, Actual:7788
et-core.go:28:
/Users/llj/mygithub/src/github.com/tinyhubs/et/examples/example2_test.go:12
Expect:sina, Actual:google
et-core.go:16:
/Users/llj/mygithub/src/github.com/tinyhubs/et/examples/example2_test.go:16
Expect:mtn, Actual:rnd
测试代码也需要良好的可维护性,所以大家写测试代码的时候往往会在断言代码附近写上注释来表达断言的意图.如下所示:
// Check the email is [email protected]
assert.Match(t, `^[a-zA-Z0-9-_]+@timo\.com$`, email)
但注释毕竟不是代码,难以得到开发人员的爱,很容易失去维护,所以如果能将断言的意图作为assert函数的一个参数,那么大家修改测试代码时就不会再忽略掉了.
这是一个很好的实践,et
也支持这种用法.et
的每个基本assert接口都支持一个i
后缀的函数,使用这些i
后缀的函数你可以在调用assert函数的时候,附上断言的意图.
如下所示,我们可以利用et
的i
系列函数将前面这个代码改成下面这样:
assert.Matchi(t, "Check the email is [email protected]", `^[a-zA-Z0-9-_]+@timo\.com$`, email)
为提高断言代码的可用性,et为每个正向断言和反向断言都提供了函数. 比如:
如果你用assert.Equal
来检测两个数据是否相等,那么你也应该知道其实您也可以使用assert.NotEqual
来检测两个数不相等.
类似的还有:
assert.Equal
vs assert.NotEqual
assert.True
vs assert.False
assert.Panic
vs assert.NoPanic
i
系列函数也是支持的:
assert.Equali
vs assert.NotEquali
assert.Truei
vs assert.Falsei
assert.Panici
vs assert.NoPanici
假设一个场景,我们现在需要一个判断某个整数是否在某个范围之内的断言怎么办?这个是et默认没有提供的断言.
但是,聪明如你,你一定会想到其实可以用assert.True
来实现这个断言.所以你可能会这样写代码:
assert.True(t, (value >= min) && (value <= max))
这个代码可以工作,但是我们总有那么点遗憾:为啥et不提供一个assert.Inrange
的断言函数呢?这样咱们就可以这样写代码了:
assert.Inrange(t, min, max, value)
其实,et提供了一种机制可以帮你实现自己的断言.
采用这种方式时,需要你提供一个实现了et.Assertor
接口的类,您可以这样做:
type Inrange struct {
Min int
Max int
Value int
}
func (i *Inrange) Assert() error {
if (i.Value >= i.Min) && (i.Value <= i.Max) {
return nil
}
return fmt.Errorf("Expect in range [%v, %v], Actual: %v", i.Min, i.Max, i.Value)
}
然后,这样使用(注意需要先import "github.com/tinyhubs/et/et"
):
et.Assert(&Inrange{min, max, value}, t)
如果触发了断言失败,可以获得下面的结果,注意看第二行提示,这个就是我们Assertor返回的error哦:
et-core.go:16:
/Users/llj/mygithub/src/github.com/tinyhubs/et/examples/example3_test.go:27
Expect in range [1, 100], Actual: 320
et.Assert
的用法好像跟assert.Equal
其他的不一样对吧,但其实assert.Equal也是使用上面的Assertor类似的机制实现的.
这就涉及到下面的扩展方式2.
你可以在方式1的基础上再额外提供下面一个断言函数:
func AssertInrange(t *testing.T, min int, max int, value int) {
et.AssertInner(t, "", &Inrange{min, max, value}, 2)
}
然后,方式1中的实例代码可以改成下面这样:
AssertInrange(t, min, max, value)
输出结果如下,和方式1的输出结果相同:
et-core.go:16:
/Users/llj/mygithub/src/github.com/tinyhubs/et/examples/example3_test.go:40
Expect in range [1, 100], Actual: 320
您可以在et/examples/example3_test.go
查看这个完整的扩展的示例,您可以试着运行下diamante看看效果.
如果您觉得自己开发了一个很不错的扩展,请必要忘记分享给你周边的同事,如果觉得您的扩展可以帮到更多人,那么直接发一个pull request给我吧,或许我可以合并到et中去.