David Kubecka
06/06/2024, 8:33 AMfun <T> assertEqualsRecursive(actual: T, expected: T, vararg ignoringFields: String) {
assertThat(actual)
.usingRecursiveComparison().withStrictTypeChecking().ignoringFields(*ignoringFields)
.isEqualTo(expected)
}
In my actual test case I'm capturing a list argument into a slot:
val messageValuesSlot = slot<List<SomeType>>()
val actualMessages = messageValuesSlot.captured
and then comparing it with an expected list:
assertEqualsRecursive(actualMessages, listOf(...))
The problem is that thanks to the withStrictTypeChecking
option the comparison fails with
actual and expected are considered different since the comparison enforces strict type check and expected type java.util.Arrays$ArrayList is not a subtype of actual type java.util.ArrayList
So if I understand it correctly
• There are for some reason two ArrayList
in java.util
• The listOf
constructor uses different ArrayList
than the mockk when filling the messageValuesSlot
Why is that? Why mockk doesn't use listOf
? Is there anything I can do about that other than reverse-engineer mockk and use the same ArrayList
?ephemient
06/06/2024, 8:49 AMSam
06/06/2024, 8:49 AMArrayList
. It's an unfortunate coincidence. One of them is the resizable ArrayList
class we all know and love, and the other is a fixed-size list that's created by the Arrays.asList
function.
I'd guess that mockk is using the resizable version, maybe via mutableListOf()
. Meanwhile, listOf(elements)
just returns elements.asList()
, which is nice and efficient. But these are all implementation details! You shouldn't ever need to care about the actual class that's returned by any of these functions.
Using strict type checking to compare two lists isn't going to be useful, except in the unlikely event that you actually care about specific implementation details of the list itself.Sam
06/06/2024, 8:49 AMusingRecursiveFieldByFieldElementComparator
instead?Sam
06/06/2024, 8:50 AMDavid Kubecka
06/06/2024, 8:51 AMDavid Kubecka
06/06/2024, 8:52 AM+
operator in my code whereas I'm comparing the result with a "plainly" constructed list in my test.David Kubecka
06/06/2024, 8:57 AMUsing strict type checking to compare two lists isn't going to be usefulI agree about that but I wanted to create a universal function
assertEqualsRecursive
that could be correctly used in any case. Actually, I've been using such a function for a while now but I was missing the withStrictTypeChecking
option which lead to issues such as Err(SomeError)
and Err(OtherError)
were considered equal (SomeError
and OtherError
are data objects). So now I have fixed a false positive but encountered a false negative at a different place 🙂Sam
06/06/2024, 8:59 AMErr(SomeError)
and Err(OtherError)
are considered equal then it sounds like you have a bug in your equals
implementation for the Err
class…David Kubecka
06/06/2024, 9:04 AMErr(SomeError).equals(Err(OtherError))
is false. I'm probably missing another piece of config of assertThat
. Let me check.David Kubecka
06/06/2024, 9:10 AMusingOverriddenEquals
.Sam
06/06/2024, 9:12 AMequals
by default. I hadn't considered that two data objects would be considered equal when doing a recursive comparison like that, but it makes sense! After all, their only distinguishing feature is their type.David Kubecka
06/06/2024, 9:13 AMthat two data objects would be considered equal when doing a recursive comparisonYeah, it also wasn't totally obvious to me at first 🙂
David Kubecka
06/06/2024, 9:15 AMequals
sadly breaks other cases 😞 They involve data classes and the ignoringFields
feature. Not sure yet which is the culprit.David Kubecka
06/06/2024, 9:17 AMignoringFields
and usingOverriddenEquals
are simply incompatible because by using equals
for the comparison you are completely delegating the comparison to the class method.David Kubecka
06/06/2024, 9:18 AMDavid Kubecka
06/06/2024, 9:20 AMSam
06/06/2024, 9:21 AMDavid Kubecka
06/06/2024, 9:25 AM