前言
2016年我写过一篇关于Go语言单元测试的文章,简单介绍了 testing 库的使用方法。后来发现 testify/require 和 testify/assert 可以大大简化单元测试的写法,完全可以替代 t.Fatalf
和 t.Errorf
,而且代码实现更为简短、优雅。
再后来,发现了 mockery
库,它可以为 Go interface 生成一个 mocks struct。通过 mocks struct,在单元测试中我们可以模拟所有 normal cases 和 corner cases,彻底消除细节实现上的bug。
mocks 在测试无状态函数 (对应 FP 中的 pure function) 中意义不大,其应用场景主要在于处理不可控的第三方服务、数据库、磁盘读写等。如果这些服务的调用细节已经被封装到 interface 内部,调用方只看到了 interface 定义的一组方法,那么在测试中 mocks 就能控制第三方服务返回任意期望的结果,进而实现对调用方逻辑的全方位测试。
关于 interface 的诸多用法,我会单独拎出来一篇文章来讲。本文中,我会通过两个例子展示 testify/require
和 mockery
的用法,分别是:
使用
testify/require
简化 table driven test使用
mockery
和testify/mock
为 lazy cache 写单元测试
小提示:由于后方代码较多,对于小屏幕设备,建议横屏阅读代码。
准备工作
go get github.com/stretchr/testify
go get github.com/vektra/mockery/.../
testify/require
首先,我们通过一个简单的例子看下 require 的用法。我们针对函数 Sqrt
进行测试,其实现为:
func Sqrt(xfloat64) float64 {
if x < 0 {
panic("cannot be negative")
}
if x == 0 {
return 0
}
a := x / 2
b := (a + 2) / 2
erro := a - b
for erro >= 0.000000001 || erro <=-0.000000001 {
a = b
b = (b + x/b) / 2
erro = a - b
}
return b
这里我们使用了一个常规的方法实现 Sqrt
,该实现的最大精确度是到小数点后9位(为了方便演示,这里没有对超出9位的部分进行删除)。我们首先测试 x < 0
导致 panic 的情况,看 require
如何使用,测试代码如下:
func TestSqrt_Panic(t *testing.T) {
defer func() {
r := recover()
require.Equal(t, "cannot be negative", r)
}()
_ = Sqrt(-1)
在上面的函数中,我们只使用 require.Equal
一行代码就实现了运行结果校验。如果使用 testing</