1

I'm wondering if I can do a global config for a test. I know that I can compare this object something like that:

x.Should().BeEquivalentTo(y, opt => opt.Excluding(z => z.Member)

But I want all the methods in my test to use this config.

Sergеу Isupov
  • 504
  • 1
  • 8
  • 20

1 Answers1

2

To exclude a member from a specific type, you can create a custom IMemberSelectionRule.

To use that selection rule for all tests, use the static AssertionOptions.AssertEquivalencyUsing in some setup method of your unit testing framework. Be aware that AssertionOptions.AssertEquivalencyUsing changes static state of Fluent Assertions, so if you're running tests in parallel it should be invoked before any tests are run. For NUnit that would be [OneTimeSetUp] inside a [SetUpFixture] not inside a namespace.

using FluentAssertions;
using FluentAssertions.Equivalency;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;

[SetUpFixture]
public class MySetUpClass
{
    [OneTimeSetUp]
    public void RunBeforeAnyTests()
    {
        AssertionOptions.AssertEquivalencyUsing(e => e.Using(new MyNamespace.MyClassSelectionRule()));
    }
}

namespace MyNamespace
{
    class MyOuterClass
    {
        public MyInnerClass MemberToInclude { get; set; }

        public int MemberToExclude { get; set; }
    }

    class MyInnerClass
    {
        public int AnotherMemberToInclude { get; set; }

        public int MemberToExclude { get; set; }
    }

    internal class MyClassSelectionRule : IMemberSelectionRule
    {
        public bool IncludesMembers => false;

        public IEnumerable<IMember> SelectMembers(INode currentNode, IEnumerable<IMember> selectedMembers, MemberSelectionContext context) =>
            selectedMembers.Where(e => !(e.DeclaringType.Name == nameof(MyOuterClass) && e.Name == nameof(MyOuterClass.MemberToExclude)));
    }

    [TestFixture]
    public class UnitTest1
    {
        [Test]
        public void Ignore_the_member_MemberToExclude_on_MyOuterClass()
        {
            var subject = new MyOuterClass
            {
                MemberToInclude = new MyInnerClass
                {
                    AnotherMemberToInclude = 42,
                    MemberToExclude = 42
                },
                MemberToExclude = 1
            };

            var expectation = new MyOuterClass
            {
                MemberToInclude = new MyInnerClass
                {
                    AnotherMemberToInclude = 42,
                    MemberToExclude = 42
                },
                MemberToExclude = 2
            };

            subject.Should().BeEquivalentTo(expectation);
        }

        [Test]
        public void Do_not_ignore_the_member_MemberToExclude_on_MyInnerClass()
        {
            var subject = new MyOuterClass
            {
                MemberToInclude = new MyInnerClass
                {
                    MemberToExclude = 1
                },
            };

            var expectation = new MyOuterClass
            {
                MemberToInclude = new MyInnerClass
                {
                    MemberToExclude = 2
                },
            };

            Action act = () => subject.Should().BeEquivalentTo(expectation);

            act.Should().Throw<AssertionException>();
        }
    }
}

Doug
  • 2,400
  • 2
  • 18
  • 24
Jonas Nyrup
  • 2,376
  • 18
  • 25
  • But be careful with test frameworks that run their tests in parallel. `AssertionOptions` changes the static state. – Dennis Doomen Aug 08 '19 at 15:57
  • Thank you for your answer. It works. But how can I check the type? What if I have two classes: `Foo` and `Bar` that have fields with the same name `FieldName`. I want to exclude it from `Foo` but still check it for `Bar` – Sergеу Isupov Aug 08 '19 at 19:11
  • @SergеуIsupov I've updated the example to handle multiple types with a member named `MemberToExclude` – Jonas Nyrup Aug 13 '19 at 06:05
  • 1
    Great answer and exactly what I needed! The signature for `SelectMembers` changed slightly a few years ago, so I updated your code. Thanks! – Doug May 05 '23 at 13:41