[Fluent Assertions] Object graph comparison

Last updated on

日前在撰寫單元測試時,發生測試失敗,使用 Should().BeEquivalentTo(expected) 進行物件比對,已確認 待測物件期望物件 內的資料相同,但卻出現 be it misses 造成的測試結果失敗

所使用的 FlunentAssertion Nuget 版本為 4.13.1

問題描述

為簡化問題的本身,在測試案例中,新增 待測物件期望物件 兩個物件,且資料相同。以下是測試案列與錯誤訊息。

[Fact]
public void Test()
{
    var actual = new List<Account>
    {
        new Account {Name = "T1", Money = 100},
        new Account {Name = "T2", Money = 20}
    };
    var expected = new List<Account>
    {
        new Account {Name = "T1", Money = 100},
        new Account {Name = "T2", Money = 20}
    };
    actual.Should().BeEquivalentTo(expected);
}

public class Account
{
    public string Name { get; set; }
    public decimal Money { get; set; }
}

測試錯誤訊息如下

Xunit.Sdk.XunitException
Expected collection {

TestProject1.Account
{
   Money = 100M
   Name = "T1"
},

TestProject1.Account
{
   Money = 20M
   Name = "T2"
}} to be equivalent to {

TestProject1.Account
{
   Money = 100M
   Name = "T1"
},

TestProject1.Account
{
   Money = 20M
   Name = "T2"
}}, but it misses {

TestProject1.Account
{
   Money = 100M
   Name = "T1"
},

TestProject1.Account
{
   Money = 20M
   Name = "T2"
}}.
   at FluentAssertions.Execution.XUnit2TestFramework.Throw(String message)
   at FluentAssertions.Execution.TestFrameworkProvider.Throw(String message)
   at FluentAssertions.Execution.DefaultAssertionStrategy.HandleFailure(String message)
   at FluentAssertions.Execution.AssertionScope.FailWith(String message, Object[] args)
   at FluentAssertions.Collections.CollectionAssertions`2.BeEquivalentTo[T](IEnumerable`1 expected, String because, Object[] becauseArgs)

問題排除

查詢 Should().BeEquivalentTo,發現 Fluentassertions 已經有人反應這個 issue 🔗 了。

方案一: 變更使用的方法

在 Fluentassertions Nuget 套件不升級的條件下,將 Should().BeEquivalentTo 變更為 ShouldBeEquivalentTo() 或 ShouldAllBeEquivalentTo() 就能順利通過測試。

[Fact]
public void Test()
{
    var actual = new List<Account>
    {
        new Account {Name = "T1", Money = 100},
        new Account {Name = "T2", Money = 20}
    };

    var expected = new List<Account>
    {
        new Account {Name = "T1", Money = 100},
        new Account {Name = "T2", Money = 20}
    };

    // 以下兩種驗證方式,均通過測試
    actual.ShouldBeEquivalentTo(expected);
    actual.ShouldAllBeEquivalentTo(expected);
}

方案二: 升級到 version 5.0 以上

在反應的 Issue 🔗 的最後,FluentAssertions 🔗 專案的維護者 Dennis Dooman 也回應在 5.0 以上的版本,已修正此問題。

筆者實際升級到 5.0 之後,確實也能順利通過測試。

函數小筆記

.Should().BeEquivalentTo()

  • 可用於比對 Collection, Dictionaries
  • 針對物件再次出現(recurs)的 Field 與 Properity 進行比對。預設比對方式如同 Object.Equals

.ShouldBeEquivalentTo()

  • 因為容易與 Should().BeEquivalentTo() 搞混,所以在 5.0 之後,該方法已經被拔除。

.ShouldAllBeEquivalentTo ()

  • 在 5.0 之後,該方法已經被拔除。

小結

version 5.0 beforeversion 5.0 later
.Should().ShouldBeEquivalentTo()VV
.ShouldBeEquivalentTo()V
.ShouldAllBeEquivalentTo ()V

參考資訊