【问题标题】:Compare structs that have slice fields ignoring item order with stretchr/testify比较具有忽略项目顺序的切片字段的结构与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))。我正在寻找一种比较此类结构的方法,最好不必为所有对象创建自定义比较函数。

谢谢

【问题讨论】:

    标签: unit-testing go


    【解决方案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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-19
      • 2016-11-01
      • 2018-08-16
      • 1970-01-01
      • 2021-12-23
      • 2023-03-21
      • 2014-02-21
      相关资源
      最近更新 更多