nunit icon indicating copy to clipboard operation
nunit copied to clipboard

How to add a custom comparer globally?

Open Swimburger opened this issue 9 months ago • 7 comments

I need to add a custom comparer, but I cannot modify the individual test code as that part is generated, so I can't add .Using(new CustomComparer()) to the tests myself. Is there a way to add a comparer globally so it'll automatically get applied in all comparison test constraints?

Swimburger avatar Mar 22 '25 20:03 Swimburger

What you are asking, is to be able to change default comparers. I am afraid that is not possible. For tests without the .Using( they will be using the default Equality and Comparision comparers.

These are hardcoded into the constructors for the constraints, so there are currently no way to configure those. The idea is , as you mention, that one should use the .Using( to override these.

But, you write that you have generated test code, and you need to change these defaults on a broader basis. What is it you want to change? It seems a bit strange that you should have a need for that,.

OsirisTerje avatar Mar 23 '25 04:03 OsirisTerje

What I've resorted to is to do generate the tests with .UsingDefaults() which is a method where I handwrite all the defaults.

Assert.That(
    response,
    Is.EqualTo(JsonUtils.Deserialize<Index>(mockResponse)).UsingDefaults()
);

But really, what I want is a solution where I can globally say, this is how you should compare a ReadOnlyMemory<float>, this is how you compare an IOneOf type, this is how you compare a JsonElement.

This is essentially what I'm doing in the extension method, except I have to call the extension method for each equality assertion.

    public static EqualConstraint UsingDefaults(this EqualConstraint constraint)
        => constraint.UsingPropertiesComparer()
            .UsingReadOnlyMemoryComparer<int>()
            .UsingReadOnlyMemoryComparer<uint>()
            .UsingReadOnlyMemoryComparer<long>()
            .UsingReadOnlyMemoryComparer<ulong>()
            .UsingReadOnlyMemoryComparer<string>()
            .UsingReadOnlyMemoryComparer<bool>()
            .UsingReadOnlyMemoryComparer<float>()
            .UsingReadOnlyMemoryComparer<double>()
            .UsingOneOfComparer()
            .UsingJsonElementComparer();

Swimburger avatar Mar 23 '25 17:03 Swimburger

@Swimburger I agree this could be done, that is, allow the defaults to be configurable.
Would you like to do a PR for that ?

OsirisTerje avatar Apr 05 '25 16:04 OsirisTerje

Yes, I would be willing to try. Any pointers appreciated tho!

Swimburger avatar Apr 05 '25 18:04 Swimburger

Take a look at the ComparisonAdapter. Is has a static Default property. Which again uses the standard NUNitComparer. You need to make this configurable. I would assume you would have to do some digging around these concepts.

Tip: Clone the nunit repo, include the nunit source code for the framework in a repro solution of your own, and debug step through the parts of interest.

OsirisTerje avatar Apr 15 '25 17:04 OsirisTerje

@Swimburger Any progress? If you have done something, it would be nice to raise the PR, you can also raise it as a draft PR.

OsirisTerje avatar May 15 '25 14:05 OsirisTerje

@OsirisTerje No, I haven't had time to work on this.

Swimburger avatar May 15 '25 15:05 Swimburger