0

Recently I answered SO question describing how to avoid internal object state validation in FluentAssertions. Now I faced the same problem and wondering why does FluentAssertions validate internal properties OOTB?

public class Class1
{
    [Fact]
    public void CompareCultureInternalFields()
    {
        var foo1 = new Foo();
        var foo2 = new Foo();

        foo1.ShouldBeEquivalentTo(foo2); // fails
    }

    public object Culture { get; set; }
}

public class Foo
{
    public Foo()
    {
        InternalProp = Guid.NewGuid();
    }

    internal Guid InternalProp { get; }
}

Exception details:

Xunit.Sdk.XunitException: Expected member InternalProp to be {61625b04-c4e6-4e08-a45a-5ff8bb7d53e7}, but found {df589d73-e382-4104-8157-a41da2ca17f5}.

With configuration:
- Use declared types and members
- Compare enums by value
- Match member by name (or throw)
- Be strict about the order of items in byte arrays

Shouldn't the foo1 and foo2 objects be equivalent for a consumer who deals with the public API?

Community
  • 1
  • 1
Serhii Shushliapin
  • 2,528
  • 2
  • 15
  • 32
  • In your example you should not be able to access internal property if the class is in another assembly/project. This is not a good example if the classes are in the same assembly – Nkosi Jan 30 '17 at 10:37
  • Good point. What if I rewrite the sample with some auto-generated internal field? – Serhii Shushliapin Jan 30 '17 at 10:40
  • Ok now I understand what you mean. – Nkosi Jan 30 '17 at 10:40
  • I made the `InternalProp` readonly. Now it just stores some auto-generated value which should address your concern about 'cross-project' access. Does it look more correct now? – Serhii Shushliapin Jan 30 '17 at 10:48
  • Yes. looking at the source code of project now. i suspect they are using reflection and grabbing all the properties. – Nkosi Jan 30 '17 at 10:49
  • 1
    That was a choice made by the author of FluentAssertions. No-one but the author can answer why they made that choice. Do I think it was a good choice? That's a matter of opinion and this is not the place to discuss opinions. – Mike Stockdale Jan 30 '17 at 21:49
  • @SergeyShushlyapin Did you find out any more info, or did you ask on the [GitHub FluentAssertions page](https://github.com/fluentassertions/fluentassertions)? – Ayb4btu May 22 '17 at 07:14
  • Nope. For myself I made a conclusion that implementing `Equals` method in my entities provides better experience for the API consumers. When I need to compare two entities in unit tests only, FluentAssertions is a good choice. When I need to compare them somewhere else, that become a problem since the comparison logic start appearing in numerous places (and may vary). – Serhii Shushliapin May 22 '17 at 07:36

1 Answers1

1

I've tried to trace it back all the way to the origins of the repo, but apparently it has always been like that. In a way, internal properties are conceptually public. If you really want to design them as not being part of the your public API, make them private. Another reason why you might run into this problem is that you're testing scope might be a bit on the small side. Why would you make some properties public and others internal? Again, this is just an presumption by me, and you may have good reasons to do so. You can always exclude that internal property though.

Noctis
  • 11,507
  • 3
  • 43
  • 82
Dennis Doomen
  • 8,368
  • 1
  • 32
  • 44