Golang中如何自动编写单元测试?

Golang中如何自动编写单元测试? 大家好,各位Gopher!

有没有什么软件可以扫描一个 .go 文件,识别其中的公共方法,然后为其编写单元测试?

我找到了两个,但它们都有一个巨大的缺点:

GitHub

cweill/gotests

头像

从您的源代码生成 Go 测试。通过创建 GitHub 帐户为 cweill/gotests 的开发做出贡献。

GitHub

hexdigest/gounit

头像

Go 编程语言的单元测试生成器。通过创建 GitHub 帐户为 hexdigest/gounit 的开发做出贡献。

这两个工具都是扫描文件并编写单元测试桩代码。

虽然这非常好,但我正在寻找更进一步的功能:查看公共方法的参数,随机生成 N 组这样的参数组合,并用这些组合调用该方法 N 次。

最后,为这 N 组参数组合编写 N 个单元测试,期望测试结果与最近运行这 N 次方法所返回的结果一致。

这些使用随机数据的测试将构成一套单元测试,以防止错误的代码重构。这样的软件存在吗?欢迎就此提出任何建议。


更多关于Golang中如何自动编写单元测试?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

即便如此,我仍怀疑其价值。以 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
}

这些工具可以自动生成随机输入数据,但需要你定义要验证的属性或条件。对于防止错误的代码重构,属性测试特别有用,因为它可以验证代码的数学属性或不变性,而不仅仅是特定的输入输出对。

回到顶部