[Unit Test] 測試程式中的比對物件

結果與期望比對,是測試程式碼中最重要的一個步驟,就是用它來取代人眼比對,有關物件比對 91哥的文章有非常詳細的介紹:

https://dotblogs.com.tw/hatelove/2014/06/06/how-to-assert-two-collection-equal

https://dotblogs.com.tw/hatelove/2016/03/28/compare-object-equality-with-expected-objects

當測試程式碼用的是複雜型別,會比對型別中的屬性狀態(值),用它來決定是否通過驗證,最直接的方式就是跑迴圈一個一個比,這樣做不是很聰明,也不夠快,太費力

我會使用以下物件來完成我的工作

  1. FluentAssertions
  2. SpecFlow

在這裡我分享我常用的比對方式...

開發環境

  • Windows 10 Enterprise x64 CHT
  • VS 2015 Update2 Eng
  • FluentAssertions 4.9
  • SpecFlow 2.1

 

FluentAssertions

Nuget 上的 FluentAssertions 提供了相當多的比對方式,其中複雜型別的比對可通過 ShouldBeEquivalentTo | ShouldAllBeEquivalentTo 方法實現

它可以
Anonymous Type Compare
Anonymous Collection Type Compare
Anonymous and Name Type Compare

[TestMethod]
public void 具名型別集合和具名型別集合比較()
{
    var expected = new List<Product>()
    {
        new Product { ID=1,Name="pen",Price=2.22m,Remark = "我爸的筆"},
        new Product { ID=2,Name="book",Price=4.96m ,Remark = "我爸的書"},
    };
    var actual = new List<Product>()
    {
        new Product { ID=1,Name="pen",Price=2.22m,Remark = "我爸的筆"},
        new Product { ID=2,Name="book",Price=4.96m ,Remark = "我爸的書"},
    };

    expected.ShouldBeEquivalentTo(actual);
}

 

在某些情況下,我只比某些欄位,其餘欄位不重要,我不要比,expected 沒有 Remark 這個欄位,測試仍然亮綠燈

[TestMethod]
public void 匿名型別集合和具名型別集合比較()
{
    var expected = new[]
    {
        new { ID=1,Name="pen",Price=2.22m },
        new { ID=2,Name="book",Price=4.96m },
    };

    var actual = new List<Product>()
    {
        new Product { ID=1,Name="pen",Price=2.22m,Remark = "我爸的筆"},
        new Product { ID=2,Name="book",Price=4.96m ,Remark = "我爸的書"},
    };

    expected.ShouldBeEquivalentTo(actual);
}

 

FluentAssertions 只會比 expected 存在的項目,不理會 actual

[TestMethod]
public void 匿名型別和具名型別比較()
{
    var expected = new { ID = 1, Name = "pen", Price = 2.22m };
    var actual = new Product { ID = 1, Name = "pen", Price = 2.22m, Remark = "我爸的筆" };

    expected.ShouldBeEquivalentTo(actual);
}

比對單一物件用 ShouldBeEquivalentTo
比對集合物件用 ShouldAllBeEquivalentTo (也可比對單一物件)

 

SpecFlow

有關資料庫的驗證,我會採用 SpecFlow 來完成多欄位的驗證,而不是 FluentAssertions,它描述多欄位需求,較容易閱讀;驗證時,也只會根據 Then 所描述的欄位下去比對(部分比對)。

Scenario: SpecFlow比較部分屬性
    Given Product資料表應有以下資料
        | ID | Name | Price | Remark    |
        | 1  | pen  | 2.22  | 我爸的筆   |
        | 2  | book | 4.96  | 我爸的書   |
    Then 我預期應在Product資料表得到以下資料
        | ID | Name | Price |
        | 1  | pen  | 2.22  |
        | 2  | book | 4.96  |

 

以下程式碼沒有真的操作資料庫,重點是 SpecFlow 的比對方法 table.CompareToSet(products)

[Given(@"Product資料表應有以下資料")]
public void GivenProduct資料表應有以下資料(Table table)
{
    var products = table.CreateSet<Product>();
    ScenarioContext.Current.Add("products", products);
}

[Then(@"我預期應在Product資料表得到以下資料")]
public void Then我預期應在Product資料表得到以下資料(Table table)
{
    var products = ScenarioContext.Current.Get<IEnumerable<Product>>("products");
    table.CompareToSet(products);
}

比對單一物件用 table.CompareToInstance()
比對集合物件用 table.CompareToSet()

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo