2010-02-05 118 views
13

我的單元測試中有兩個對象,實際和預期的對象。對象方法的所有屬性都完全相同,如果我運行以下測試:單元測試中的對象比較

Assert.AreEqual(expectedObject.Property1, actualObject.Property1); 

結果按預期通過。但是,當我嘗試運行下列測試時,它會失敗:

Assert.AreEqual (expectedObject, actualObject); 

我錯過了什麼?兩個對象可以不能比較嗎?我必須對每個屬性進行檢查嗎?

+2

下面是NUnit的一個類似的問題,這將是有益的:http://stackoverflow.com/questions/318210/compare-equality-between-two-objects-in-nunit – 2010-02-05 14:23:15

+0

的實際執行你想寫的工作,我寫了一個工具類,通過使用反射來比較兩個對象的屬性。目前我沒有手頭的代碼,但實現這樣的功能並不困難。 – Juri 2010-02-05 14:25:07

+0

如果你遇到那個代碼Juri,我很想看看你做了什麼。 – 2010-02-05 14:29:49

回答

15

您需要爲您的對象覆蓋EqualsAssert使用Object.Equals。默認情況下,引用類型的對象上的Object.Equals執行引用比較。也就是說,引用類型的兩個實例當且僅當它們引用同一個對象時是相等的。您希望覆蓋此值,以便不執行參考比較,而是執行值比較。關於這個問題,這是一個很好的MSDN article。請注意,您還需要覆蓋GetHashCode。請參閱MSDN guidelines。下面是一個簡單的例子:

前:

​​

後:

class Test { 
    public int Value { get; set; } 
    public override bool Equals(object obj) { 
     Test other = obj as Test; 
     if(other == null) { 
      return false; 
     } 
     return this.Value == other.Value; 
    } 
    public override int GetHashCode() { 
     return this.Value.GetHashCode(); 
    } 
} 

Test first = new Test { Value = 17 }; 
Test second = new Test { Value = 17 }; 
Console.WriteLine(first.Equals(second)); // true 
+0

你能詳細解釋一下嗎? – 2010-02-05 14:22:03

+2

小心平等污染。重寫Equals可能不是正確的做法。有關詳細信息,請參閱此處:http://stackoverflow.com/questions/2046121/how-to-compare-two-object-in-unit-test-how-to-compare-two-collection-in-unit-tes/ 2047576#2047576 – 2010-02-05 15:23:43

4

第二斷言語句實際上比較對象的引用,而不是內容。由於AreEqual方法的參數是類型對象,因此沒有太多關於單元測試框架應如何比較它們的信息。

編輯:查了這個問題:Compare equality between two objects in NUnit

+1

ah..too遲了:)只是寫着同樣的:)(+1) – Juri 2010-02-05 14:24:00

+0

啊啊,好電話。我發佈時沒有看到nUnit問題。 – 2010-02-05 14:30:17

1

你不能使用「=」號,除非你已經是超負荷您的對象。在您的對象類中,您需要執行以下操作:


public override bool Equals(object obj) 
{ 
    if(obj == null) 
     return false; 
    return (this.Property1 == obj.Property1 && 
      this.Property2 == obj.Property2); 
} 

如果您不這樣做,那麼您只是簡單地比較對象引用。

1

這是事實。兩個對象是否相等完全取決於其Equals方法的實現。有時候用Equal方法,覆蓋GetHashCode實現也是很好的。如果它不是覆蓋,則默認虛擬實現(Object類)將與Equal方法的評估一起考慮。爲了使對象被認爲相同,它們的哈希碼應該是相同的。

但是對於單元測試,我建議不要在很大程度上依賴於平等方法的實現。無論您希望確定的屬性如何自己比較對象的屬性,因爲Equal方法可能是自定義實現,所以有可能在一天結束時包含錯誤。所以更好的信任系統定義的類的單元測試的Equal方法。

0

https://github.com/kbilsted/StatePrinter已明確寫入轉儲對象圖,以字符串表示與易寫單元測試的目的。

  • 它來自witg Assert方法,輸出正確轉義的字符串容易複製粘貼到測試中來糾正它。
  • 它允許單元測試自動重新編寫
  • 它與所有的單元測試集成構架
  • 不像JSON序列化,循環引用支持
  • 您可以輕鬆地過濾,所以類型只有部分被轉儲

鑑於

class A 
{ 
    public DateTime X; 
    public DateTime Y { get; set; } 
    public string Name; 
} 

你可以在一個類型安全的方式,並使用自動完成視覺工作室包括或排除領域。

var printer = new Stateprinter(); 
    printer.Configuration.Projectionharvester().Exclude<A>(x => x.X, x => x.Y); 

    var sut = new A { X = DateTime.Now, Name = "Charly" }; 

    var expected = @"new A(){ Name = ""Charly""}"; 
    printer.Assert.PrintIsSame(expected, sut); 
0

這是典型的等價問題,看起來像接受的答案是不是一個好一個。我會盡力解釋原因。

想象一下 - 您必須在您的後端編寫集成測試以確保它將您的域對象保存爲正確。 你有一個代碼:

[TestMethod] 
    [Description(@"Sequentially perform operations 
       1. Save new item in DB 
       2. Get same Item from DB 
       Ensure that saved and get Items are equivalent")] 
    public void Repository_Create_Test() 
    { 
     var initialItem = GetTestItem(); 
     //create item and check it is created correct 
     initialItem.ID = repository.Create(initialItem, userID, ownerID); 
     Item resultItem = repository.GetById(initialItem.ID, ownerID); 
     resultItem.Should().NotBeNull(); 
     Assert.AreEqual(initialItem, resultItem); 
    } 

所以,你需要驗證從存儲讀取對象是絕對相當於我們已經發送到存儲的對象。覆蓋Equals是一個簡單的首先猜測。對於這種情況,我們需要設置Equals來比較所有對象字段。但從DDD的角度來看,這顯然是錯誤的。域實體由不可變密鑰(或主鍵)區分,而不是由所有可變域區分。所以,如果我們對人力資源領域進行建模並假設'Mister X'有一個新的電話號碼,那麼他仍然是'X先生'。

所有這一切,我目前正在使用FluentAssertions框架,具有相當強大的等效性檢查設施。就像這樣:

resultItem.ShouldBeEquivalentTo(initialItem);