2

I have a class called HandRank which has an Id property. The Id property is generated by my database.

public class HandRank
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public int Rank { get; set; }
}

I have a method called GetHandRanks which returns a Dictionary<string, HandRank>.

In my tests, I am seeding an in memory database. As the Id property is determined by the database, I wish to exclude it from my assertion.

Below is my test but it fails because The Id property is not set in the expectedResult. I am not setting the Id because I do not know what the Id will be when generated by the database.

[Test]
public void Test()
{
    // arrange
    var expectedResult = new Dictionary<string, HandRank>
    {
        { "aaa", new HandRank { Rank = 1} },
        { "bbb", new HandRank { Rank = 2} }
    };

    // act
    var actualResult = _handRankManager.GetHandRanks();

    // Assert
    actualResult.Should().BeEquivalentTo(expectedResult);
}

I expect that the assertion will need to be something like the below but I cannot get the lambda in the Excluding method correct.

actualResult.Should().BeEquivalentTo(expectedResult, options => options.Excluding(x => x.Values.Id));
Tolvic
  • 125
  • 1
  • 7

2 Answers2

6

Firstly, if you only want to filter out HandRank.Id, then you could use the following:

actualResult.Should().BeEquivalentTo(expectedResult, opt =>
    opt.Excluding(m => 
        m.SelectedMemberInfo.DeclaringType == typeof(HandRank) 
        && m.SelectedMemberInfo.Name.Equals(nameof(HandRank.Id))
    ));

If ignoring properties named "Id" is something you want to use in many parts of your test, you're better off taking it out into a function like this:

public static EquivalencyAssertionOptions<_> ExcludeId<_>(EquivalencyAssertionOptions<_> opt)
    => opt.Excluding(m => m.SelectedMemberInfo.Name.Equals("Id"));

And use it as so:

actual.Should().BeEquivalentTo(expected, ExcludeId);

Should work against Dictionaries, Lists, objects with deep properties, anything you can think of. It will blanket ignore all members named Id.


Edit 2022:

As per feedback below, 6.0 had a breaking change that flattened SelectedMemberInfo properties into IMemberInfo, which makes the exclusion nicer to read.

actual.Should().BeEquivalentTo(expected, opt =>
  opt.Excluding(member => 
    member.DeclaringType == typeof(X) 
    && member.Name.Equals(nameof(X.Id))
  ));
NPras
  • 3,135
  • 15
  • 29
  • 1
    Notes: You will need `using FluentAssertions.Equivalency;` As of version 6, you don't need `SelectedMemberInfo` anymore. Source: https://fluentassertions.com/releases/ – user1007074 Jun 27 '22 at 10:12
1

I tried the answers mentioned in this question(none of them worked for me), but for me, the way of excluding work successfully is below.

actual.Should().BeEquivalentTo(expected, opt =>
                opt.For(m => m.Values).Exclude(x => x.Id));

This is with version 6.7.0

Manojb86
  • 271
  • 2
  • 5
  • 13