比较具有忽略项目顺序的切片字段的结构与stretchr/testify
Posted
技术标签:
【中文标题】比较具有忽略项目顺序的切片字段的结构与stretchr/testify【英文标题】:Compare structs that have slice fields ignoring item order with stretchr/testify 【发布时间】:2021-12-26 13:17:38 【问题描述】:我有一个问题,我需要将两个非常大的结构(生成的 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
我尝试过使用assert.Equal(t, exp, act)
和assert.True(t, reflect.DeepEqual(exp, act))
。我正在寻找一种比较此类结构的方法,最好不必为所有对象创建自定义比较函数。
谢谢
【问题讨论】:
【参考方案1】:您可以使用assert.ElementsMatch
比较两个切片不考虑元素排序。
ElementsMatch 断言指定的 listA(array, slice...) 等于指定的 listB(array, slice...) 忽略元素的顺序。如果存在重复元素,则它们在两个列表中的出现次数应匹配。
但这仅适用于切片字段本身。如果你的结构体模型的字段很少,你可以一一比较,在切片上使用ElementsMatch
:
assert.Equal(t, exp.Foo, act.Foo)
assert.ElementsMatch(t, exp.Offs, act.Offs)
如果你的结构体有很多字段,你可以将切片值重新赋值给临时变量,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
如果stretchr/testify
允许为用户定义的类型注册自定义比较器,或者检查对象是否实现某个接口并调用它来测试相等性,那就更好了
if cmp, ok := listA.(Comparator); ok
cmp.Compare(listB)
但我不知道有这样的功能。
另外,建议使用https://github.com/r3labs/diff
,您可以照此使用。默认情况下会忽略 order 或 slice 项。
// import "github.com/r3labs/diff/v2"
changelog, err := diff.Diff(exp, act)
assert.NoError(t, err)
assert.Len(t, changelog, 0)
【讨论】:
以上是关于比较具有忽略项目顺序的切片字段的结构与stretchr/testify的主要内容,如果未能解决你的问题,请参考以下文章