Golang中如何自动编写单元测试?
Golang中如何自动编写单元测试? 大家好,各位Gopher!
有没有什么软件可以扫描一个 .go 文件,识别其中的公共方法,然后为其编写单元测试?
我找到了两个,但它们都有一个巨大的缺点:
cweill/gotests
从您的源代码生成 Go 测试。通过创建 GitHub 帐户为 cweill/gotests 的开发做出贡献。
hexdigest/gounit
Go 编程语言的单元测试生成器。通过创建 GitHub 帐户为 hexdigest/gounit 的开发做出贡献。
这两个工具都是扫描文件并编写单元测试桩代码。
虽然这非常好,但我正在寻找更进一步的功能:查看公共方法的参数,随机生成 N 组这样的参数组合,并用这些组合调用该方法 N 次。
最后,为这 N 组参数组合编写 N 个单元测试,期望测试结果与最近运行这 N 次方法所返回的结果一致。
这些使用随机数据的测试将构成一套单元测试,以防止错误的代码重构。这样的软件存在吗?欢迎就此提出任何建议。
更多关于Golang中如何自动编写单元测试?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
即便如此,我仍怀疑其价值。以 strings.Split 为例,这是一个非常简单的此类函数——接收一个输入字符串和一个分隔符。用随机字符串对两者进行五次调用,并不能提供关于其行为的有用信息。
func main() {
fmt.Println("hello world")
}
更多关于Golang中如何自动编写单元测试?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
calmh:
总体上对此持怀疑态度。当然,有一些数学上的纯函数行为类似,可以以这种方式进行测试。然而,许多其他函数接收接口和复杂类型,如数据库连接、套接字、模板……为这些自动生成随机代码不会产生有效的结果。
数据库连接、套接字、模板——这些都不是纯函数。我不期望它能对此生效。
这个测试想法只需要对纯函数(无外部参数、随机性、系统调用)和简单的数值/字符串参数生效。
我对此方法在一般情况下能否良好运作持怀疑态度。确实,存在一些数学上的纯函数具有此类特性,并且可以通过这种方式进行测试。然而,许多其他函数接收接口和复杂类型,例如数据库连接、套接字、模板……为这些类型自动生成随机代码不太可能产生有效的结果。
在Go语言中,确实有工具可以生成基于随机数据的单元测试。你可以考虑使用以下工具:
flyingmutant/rapid
这是一个基于属性测试(property-based testing)的库,可以自动生成随机输入数据来测试代码的特定属性。
示例代码:
假设你有一个简单的函数:
package math
func Add(a, b int) int {
return a + b
}
使用rapid可以这样编写测试:
package math
import (
"testing"
"github.com/flyingmutant/rapid"
)
func TestAdd(t *testing.T) {
rapid.Check(t, func(t *rapid.T) {
a := rapid.Int().Draw(t, "a").(int)
b := rapid.Int().Draw(t, "b").(int)
result := Add(a, b)
// 测试加法交换律
if result != Add(b, a) {
t.Fatalf("加法不满足交换律: %d + %d = %d", a, b, result)
}
// 测试加法结合律
c := rapid.Int().Draw(t, "c").(int)
if Add(Add(a, b), c) != Add(a, Add(b, c)) {
t.Fatalf("加法不满足结合律")
}
})
}
leanovate/gopter
这是另一个属性测试库,可以生成随机参数并验证代码属性。
示例代码:
package math
import (
"testing"
"github.com/leanovate/gopter"
"github.com/leanovate/gopter/gen"
"github.com/leanovate/gopter/prop"
)
func TestAddProperties(t *testing.T) {
parameters := gopter.DefaultTestParameters()
parameters.MinSuccessfulTests = 100
properties := gopter.NewProperties(parameters)
properties.Property("加法交换律", prop.ForAll(
func(a, b int) bool {
return Add(a, b) == Add(b, a)
},
gen.Int(),
gen.Int(),
))
properties.Property("加法结合律", prop.ForAll(
func(a, b, c int) bool {
return Add(Add(a, b), c) == Add(a, Add(b, c))
},
gen.Int(),
gen.Int(),
gen.Int(),
))
properties.TestingRun(t)
}
dvyukov/go-fuzz
这是一个覆盖率指导的模糊测试工具,可以自动生成测试用例。
示例代码:
package math
import (
"bytes"
"encoding/binary"
)
func Fuzz(data []byte) int {
if len(data) < 8 {
return 0
}
a := int(binary.BigEndian.Uint32(data[0:4]))
b := int(binary.BigEndian.Uint32(data[4:8]))
_ = Add(a, b)
return 1
}
这些工具可以自动生成随机输入数据,但需要你定义要验证的属性或条件。对于防止错误的代码重构,属性测试特别有用,因为它可以验证代码的数学属性或不变性,而不仅仅是特定的输入输出对。

