Skip to content

Instantly share code, notes, and snippets.

@sfate
Last active January 6, 2023 18:40
Show Gist options
  • Save sfate/580186c0c44ee29f1f3649003522ba95 to your computer and use it in GitHub Desktop.
Save sfate/580186c0c44ee29f1f3649003522ba95 to your computer and use it in GitHub Desktop.
[go] Test equality for two structs with human readable output

TL;DR

Function that provides ability to compare two structs in human-readable diff output with testify package. Try it online: https://go.dev/play/p/1v288fhRk9T

Legend

testify package for golang provides Equal function to compare structs (lists, arrays, etc). Unfortunately, it doesn't prints actual values for time objects in output diff.

e.g.

expectedTime, _ := time.Parse("2006-01-02", "2020-05-22")
actualTime, _ := time.Parse("2006-01-02", "2020-05-21")

expected := &event{
	StartAt: &expectedTime,
	Name:    "some val",
}
actual := &event{
	StartAt: &actualTime,
	Name:    "some val",
}

require.Equal(t, expected, actual)

For two structs with different values per time defined fields - it's output results into diff with pointers:

=== RUN   TestComparisonOutput
	Error:      	Not equal: 
					expected: &main.event{StartAt:time.Date(2020, time.May, 22, 0, 0, 0, 0, time.UTC), Name:"some val"}
					actual  : &main.event{StartAt:time.Date(2020, time.May, 21, 0, 0, 0, 0, time.UTC), Name:"some val"}
					
					Diff:
					--- Expected
					+++ Actual
					@@ -3,3 +3,3 @@
						wall: (uint64) 0,
					-  ext: (int64) 63725702400,
					+  ext: (int64) 63725616000,
						loc: (*time.Location)(<nil>)
	Test:       	TestComparisonOutput/check_comparison_output
FAIL

Solution example

expectedTime, _ := time.Parse("2006-01-02", "2020-05-22")
actualTime, _ := time.Parse("2006-01-02", "2020-05-21")

expected := &event{
	StartAt: &expectedTime,
	Name:    "some val 1",
}
actual := &event{
	StartAt: &actualTime,
	Name:    "some val",
}

equalStruct(t, expected, actual)

Following example basically mimics Equal functionality from testify package with slight change of output format:

=== RUN   TestComparisonOutput
	Error:      	Not equal: 
					expected: &main.event{StartAt:time.Date(2020, time.May, 22, 0, 0, 0, 0, time.UTC), Name:"some val"}
					actual  : &main.event{StartAt:time.Date(2020, time.May, 21, 0, 0, 0, 0, time.UTC), Name:"some val"}
					
					Diff:
					--- Expected
					+++ Actual
					@@ -1,3 +1,3 @@
						(*main.event)({
					- StartAt: (*time.Time)(2020-05-22 00:00:00 +0000 UTC),
					+ StartAt: (*time.Time)(2020-05-21 00:00:00 +0000 UTC),
						Name: (string) (len=8) "some val"
	Test:       	TestComparisonOutput/check_comparison_output
FAIL
package main
import (
"fmt"
"testing"
"time"
"github.com/davecgh/go-spew/spew"
"github.com/pmezard/go-difflib/difflib"
"github.com/stretchr/testify/assert"
)
type event struct {
StartAt *time.Time
Name string
}
func TestComparisonOutput(t *testing.T) {
t.Run("check comparison output", func(t *testing.T) {
expectedTime, _ := time.Parse("2006-01-02", "2020-05-22")
actualTime, _ := time.Parse("2006-01-02", "2020-05-21")
expected := &event{
StartAt: &expectedTime,
Name: "some val 1",
}
actual := &event{
StartAt: &actualTime,
Name: "some val",
}
equalStruct(t, expected, actual)
})
}
func diff(expected interface{}, actual interface{}) string {
spewConfigStringerEnabled := spew.ConfigState{
Indent: " ",
DisablePointerAddresses: true,
DisableCapacities: true,
SortKeys: true,
MaxDepth: 10,
}
e := spewConfigStringerEnabled.Sdump(expected)
a := spewConfigStringerEnabled.Sdump(actual)
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
A: difflib.SplitLines(e),
B: difflib.SplitLines(a),
FromFile: "Expected",
FromDate: "",
ToFile: "Actual",
ToDate: "",
Context: 1,
})
return "\n\nDiff:\n" + diff
}
func equalStruct(t *testing.T, expected interface{}, actual interface{}) bool {
if !assert.ObjectsAreEqual(expected, actual) {
diff := diff(expected, actual)
failure := fmt.Sprintf("Not equal: \n"+
"expected: %#v\n"+
"actual : %#v%s", expected, actual, diff)
return assert.Fail(t, failure)
}
return true
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment