Open Southclaws opened 2 years ago
+1
Could be some kind of extension, similar to Hamcrest used in Java to implement Matchers. Something similar is already in place with mock.MatchedBy
, but just for parameters evaluation/comparision.
One of the other issues I forgot to mention here is the need to define equality.
The example above uses Shopspring's decimal library, which is a FPA decimal type. This type can represent the same number in a variety of ways, by moving the exponent along a specific value. 1234 with an exponent of -1 is the same as 12340 with an exponent of -2 for example. Semantically, these are the same number, but when diff'd, there's no way to teach the comparison code about this type of semantic equality, it only cares about the byte-for-byte equality.
I feel diff for time.Time
is also unreadable.
Elsewhere, we extended DeepEqual
with a couple of features. Via tags:
https://github.com/weaveworks/scope/blob/477f6782f4622451723b2856bea49dca64052e53/test/reflect/deepequal.go#L146-L149
and to call a DeepEqual
method if defined on the values:
https://github.com/weaveworks/scope/blob/477f6782f4622451723b2856bea49dca64052e53/test/reflect/deepequal.go#L60-L66
I'm building a personal finance app using decimal
library and I've also found quite difficult to assert on it. Let me share a couple of tricks I've used:
decimal.Decimal
, compare the String()
value.decimal.Decimal
, serialise the structs to JSON and then assert.JsonEq()
(limitation: this requires all struct fields to be exported)Up. Maybe we could register types with its comparison functions?
Something like:
testify.RegisterComparison[T any](t T, fn func(a,b T) bool )
and use it like:
testify.RegisterComparison[decimal.Decimal](t T, fn func(a,b decimal.Decimal) bool {
return a.Equals(b)
})
Wouldn't it be cleaner and simpler to have the library defer to func (t T) Equal(u T) bool
if it exists.. time.Time
and decimal.Decimal
already have that method.
Like others we've resorted to workarounds like comparing things as JSON... this would be so much nicer!
Wouldn't it be cleaner and simpler to have the library defer to
func (t T) Equal(u T) bool
if it exists..time.Time
anddecimal.Decimal
already have that method.Like others we've resorted to workarounds like comparing things as JSON... this would be so much nicer!
Some Equal
methods, such as time.Time.Equal from the standard library do not really mean the objects are equal, in that case it just means they represent the same instant. We can't defer to the Equal method without changing the definition of equal.
For this issue I would support approaches which make differences easier to understand.
I feel that this hardly progress so I've implemented customizable equality checker https://github.com/seiyab/teq. Can this help?
I tried to fulfill(see diff, I still fix more overhead, bad diff information issues) the thought of https://github.com/stretchr/testify/issues/1204#issuecomment-1716089120, but I am not sure it is good to use cmp.Compare style to register. Any suggestions?
Is there a way, or a v2 plan to provide more user friendly ways of diffing values for large structs?
Two types I make use of a lot are times and money-friendly decimals, and this combined with needing to compare large structs results in...
Which is unreadable.
For simple cases I compare the
.String()
output likea.Equal(want.String(), got.String())
which is a little more typing but it's fine for single values.The problem is when asserting structs that have many fields. I don't want to waste time pulling out all these fields into tons of assertions just so I can add
.string()
to each item.Ideally, I'd like to satisfy some comparator interface for our custom money type so diffs and comparisons are done against the rendered value not the underlying data. One other detail of decimal values is different combinations of bases and exponents can result in the same actual number. Assertions fail on this even if the actual resulting number is the same.
I've already got this, which gets me slightly nicer diffs but the comparison is still conducted against the underlying struct data, which isn't helpful for this particular case.
What would be ideal is a simple test interface:
Or maybe a way to surface better diff strings too.
go-cmp kind of solves this but it's not across all tests via an interface, it's just for a single assert - which is cumbersome to add to every test when you have hundreds.