使用测试/快速生成结构树,尊重不变量

时间:2016-08-11 22:16:58

标签: testing go

我有一个结构树,我想用testing/quick进行测试,但是将它限制在我的不变量内。

此示例代码有效:

var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
type X struct {
    HasChildren bool
    Children    []*X
}
func TestSomething(t *testing.T) {
    x, _ := quick.Value(reflect.TypeOf(X{}), rnd)
    _ = x
    // test some stuff here
}

但是,只要HasChildren = true作为一个不变量,我们就会len(Children) > 0,所以最好确保quick.Value()生成尊重(而不是发现“错误”实际存在)。

我想我可以定义一个Generate函数,它使用quick.Value()来填充所有变量成员:

func (X) Generate(rand *rand.Rand, size int) reflect.Value {
    x := X{}

    throwaway, _ := quick.Value(reflect.TypeOf([]*X{}), rand)
    x.Children = throwaway.Interface().([]*X)

    if len(x.Children) > 0 {
        x.HasChildren = true
    } else {
        x.HasChildren = false
    }

    return reflect.ValueOf(x)
}

但这太恐慌了:

  

panic:使用nil * X指针调用的值方法main.X.Generate [已恢复]

当我将儿童从[]*X更改为[]X时,它会因堆栈溢出而死亡。

文档在示例中非常薄,我在网络搜索中几乎找不到任何内容。

如何做到这一点?

1 个答案:

答案 0 :(得分:1)

查看testing/quick源代码,您似乎无法创建递归自定义生成器,而同时重用quick库工具来生成结构的数组部分,因为size参数,旨在限制递归调用的数量,不能传递回quick.Value(...)

https://golang.org/src/testing/quick/quick.go(见第50行)

在你的情况下,这导致了一个无限的树,迅速"爆炸"在每个级别有1..50个叶子(这是堆栈溢出的原因)。

如果函数quick.sizedValue()已公开,我们可以用它来完成你的任务,但不幸的是情况并非如此。

顺便说一下,因为HasChildren是一个不变的,你不能简单地把它变成一个struct方法吗?

type X struct {
    Children    []*X
}

func (me *X) HasChildren() bool {
    return len(me.Children) > 0
}

func main() {
    .... generate X ....
    if x.HasChildren() {
        .....
    }
}