将具有忽略项目顺序的切片字段的结构与stretcher/testify进行比较

Den*_*eke 7 unit-testing go

我有一个问题,我需要将两个非常大的结构(生成的 protobuf)相互比较,作为测试用例的一部分。这些结构体中有多个嵌套数组。下面是一个重现/演示该问题的简化示例。

package pkg

import (
    "github.com/stretchr/testify/assert"
    "reflect"
    "testing"
)

type structOne struct {
    Foo  string
    Offs []*structTwo
}

type structTwo struct {
    Identifier string
}

func Test_Compare(t *testing.T) {
    exp := &structOne{
        Foo: "bar",
        Offs: []*structTwo{
            {
                Identifier: "one",
            },
            {
                Identifier: "two",
            },
            {
                Identifier: "three",
            },
            {
                Identifier: "four",
            },
        },
    }

    act := &structOne{
        Foo: "bar",
        Offs: []*structTwo{
            {
                Identifier: "four",
            },
            {
                Identifier: "three",
            },
            {
                Identifier: "two",
            },
            {
                Identifier: "one",
            },
        },
    }

    assert.Equal(t, exp, act)                   // fails
    assert.True(t, reflect.DeepEqual(exp, act)) // fails
}
Run Code Online (Sandbox Code Playgroud)

我尝试过使用assert.Equal(t, exp, act)assert.True(t, reflect.DeepEqual(exp, act))。我正在寻找一种比较此类结构的方法,最好不必为所有对象创建自定义比较函数。

谢谢

bla*_*een 7

您可以用来assert.ElementsMatch比较两个切片,而不管元素顺序如何。

ElementsMatch 断言指定的 listA(array, slice...) 等于指定的 listB(array, slice...) ,忽略元素的顺序。如果存在重复元素,则两个列表中每个元素的出现次数应该匹配。

然而,这仅适用于切片字段本身。如果你的结构体模型的字段很少,你可以一一比较它们并ElementsMatch在切片上使用:

    assert.Equal(t, exp.Foo, act.Foo)
    assert.ElementsMatch(t, exp.Offs, act.Offs)
Run Code Online (Sandbox Code Playgroud)

如果您的结构有很多字段,您可以将切片值重新分配给临时变量,将nil字段取出,然后进行比较:

    expOffs := exp.Offs
    actOffs := act.Offs

    exp.Offs = nil
    act.Offs = nil

    assert.Equal(t, exp, act) // comparing full structs without Offs
    assert.ElementsMatch(t, expOffs, actOffs) // comparing Offs separately
Run Code Online (Sandbox Code Playgroud)

stretchr/testify如果允许为用户定义类型注册自定义比较器,或者检查对象是否实现某个接口并调用它来测试相等性,那就更好了

if cmp, ok := listA.(Comparator); ok { 
    cmp.Compare(listB) 
}
Run Code Online (Sandbox Code Playgroud)

但我不知道有这样的功能。


或者,https://github.com/r3labs/diff建议您可以这样使用。默认情况下会忽略顺序或切片项。

    // import "github.com/r3labs/diff/v2"
    changelog, err := diff.Diff(exp, act)
    assert.NoError(t, err)
    assert.Len(t, changelog, 0)
Run Code Online (Sandbox Code Playgroud)