I have a problem where I need to compare two very large structs (protobuf generated) with each other, as part of a test-case. These structs have multiple nested arrays in them. Below is a simplified example that reproduces / demonstrates the problem.
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
}
I have tried using assert.Equal(t, exp, act)
and assert.True(t, reflect.DeepEqual(exp, act))
. I am looking for a way to compare such structs, preferably without having to create custom comparison functions for all of objects.
Thank you
CodePudding user response:
You can use assert.ElementsMatch
to compare two slices irrespective of element ordering.
ElementsMatch asserts that the specified listA(array, slice...) is equal to specified listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, the number of appearances of each of them in both lists should match.
However this applies only to the slice field itself. If your struct model has few fields, you can compare them one by one and use ElementsMatch
on the slice:
assert.Equal(t, exp.Foo, act.Foo)
assert.ElementsMatch(t, exp.Offs, act.Offs)
If your structs have a lot of fields, you can reassign the slice values to temp variables, nil
the fields out, and then compare:
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
It would be even better if stretchr/testify
allowed registering custom comparators for user-defined types, or checking if the objects implement a certain interface and call that to test equality
if cmp, ok := listA.(Comparator); ok {
cmp.Compare(listB)
}
but I'm not aware of such a feature.
CodePudding user response:
Providing an answer to my own question because, it is one approach that works for my case.
Using this library solves the problem: https://github.com/r3labs/diff
Then I can assert the list of changes is empty. A user earlier today had provided this as answer which worked, but the answer was deleted by the user before I could reply to it.