tpierrain / NFluent

Smooth your .NET TDD experience with NFluent! NFluent is an ergonomic assertion library which aims to fluent your .NET TDD experience (based on simple Check.That() assertion statements). NFluent aims your tests to be fluent to write (with a super-duper-happy 'dot' auto-completion experience), fluent to read (i.e. as close as possible to plain English expression), but also fluent to troubleshoot, in a less-error-prone way comparing to the classical .NET test frameworks. NFluent is also directly inspired by the awesome Java FEST Fluent assertion/reflection library (http://fest.easytesting.org/)
Apache License 2.0
310 stars 53 forks source link

Possibility of adding type safe (type-aware) checks #327

Closed bartosz-jarmuz closed 1 year ago

bartosz-jarmuz commented 4 years ago

Expected Behavior

I tend to compare apples to oranges. Do you too?:) It mostly happens when my checks are as follows:

Check.That(someObject.SomeOtherThing).IsEqualTo("2");

What I should have written is

Check.That(someObject.SomeOtherThing.Value).IsEqualTo("2");

In short, is there a way to make such comparisons flagged by the compiler? Something that would tell me that I probably cannot compare an instance of SomeOtherThing to string...

Regards, Bartosz

dupdob commented 4 years ago

Thanks for this report. Sorry for the delayed answer. Current behaviour (for IsEqualTo) is intentional, mainly because IsEqualTo relies on the Equals method for the underlying type and we cannot assume which Equals overloads may be available.

Furthermore, we rely on this flexibility to support comparison to anonymous types for simplification. Regarding the example you provided, you could use this form: Check.That(SomeObject.SomeOtherThing).IsEqualTo(new {Value == "2", OtherField = 15....})

What I can propose, if it helps you, is adding a new check that would impose using the same type.

evilz commented 4 years ago

@dupdob I got what you said, but I think the issue is about string, or even Literal types:

Ìn my case the issue is about this code :

public static ICheckLink<ICheck<string>> IsEqualTo(this ICheck<string> check, object expected)
        {
            if (expected is string s)
            {
                return IsEqualTo(check, s);
            }
            else
            {
                return EqualityHelper.PerformEqualCheck(check, expected);
            }
        }

To be equal string should be compared to another string anyway. let's take an example : Check.That("myString").IsEqualTo(42) This should not compile. I prefere the compiler to break and make explicite cast on my side Check.That("myString").IsEqualTo(42.ToString())

So I do not want add something, but remove something, but I already know this will be a breaking change ...

dupdob commented 4 years ago

@evilz : this is not possible due to the design of NFluent. More specifically, this is due to how C# handles overload resolution for extension methods. Achieving what you desire implies enforcing this rule for every type, i.e. the only available signature would be Check.That<T>(T sut).IsEqualTo(T expected);, which would not only be a extremely breaking change, but would also likely be a crippling change. Also, this would not lead to the kind of compile errors you would expect, as it would raise an Ambiguous call error, not a type error (cannot convert int to string).

Hence the proposal to have a specific check for that, as in a variant of IsEqualTo with forces the expected's type to be the same as the sut's type (note that will not help with the error message anyway)

dupdob commented 4 years ago

also, I can add a rule to the NFluent's Analyzer that would spot this situations.