2014-03-04 66 views
2

我試圖寫該方法的單元測試:如何驗證模擬對象是否從模擬列表中刪除?

public void AddItem(Cart cart, Item item) 
{ 
    var duplicates = cart.Items.OfType<Item>() 
         .Where(i => i.Key == item.Key) 
         .ToList(); 

    foreach (var duplicate in duplicates) 
    { 
     cart.Items.Remove(duplicate); 
    } 

    cart.Items.Add(item); 
} 

我想驗證重複的項目(使用相同的密鑰項目)從列表中刪除添加了新的人之前。此測試失敗:

[TestMethod] 
public void AddItemRemovesDuplicateItemsFirst() 
{ 
    const int itemKey = 123; 

    var cart = new Mock<Cart>(); 

    var duplicate = new Mock<Item>(); 
    duplicate.SetupGet(m => m.Key).Returns(itemKey); 

    cart.SetupGet(m => m.Items).Returns(new List<Item> 
     { 
      duplicate.Object 
     }); 

    var addItem = new Mock<Item>(); 
    addItem.SetupGet(m => m.Key).Returns(itemKey); 

    var task = GetTask(); 
    task.AddItem(cart.Object, addItem.Object); 

    Assert.AreEqual(1, cart.Object.Items.Count); 
} 

它失敗,因爲Count是2.在另一方面,該測試通過:

[TestMethod] 
public void AddItemRemovesDuplicateItemsFirst() 
{ 
    const int itemKey = 123; 

    var cart = new Mock<Cart>(); 

    cart.SetupGet(m => m.Items).Returns(new List<Item> 
     { 
      new Item 
       { 
        Key = itemKey 
       } 
     }); 

    var addItem = new Mock<Item>(); 
    addItem.SetupGet(m => m.Key).Returns(itemKey); 

    var task = GetTask(); 
    task.AddItem(cart.Object, addItem.Object); 

    Assert.AreEqual(1, cart.Object.Items.Count); 
} 

唯一的差別是第二個不使用Mock對象爲項目清單。

我試圖避免在第二種方法中實際創建對象。我怎麼能第一個通過?

+1

爲什麼你想嘲笑這些物品?我沒有看到你孤立任何行爲,只是一個int的值,你可以在實例化的對象上做這些。 此外,有可能是我不明白的東西,但是你可以簡單地不重複的項目添加到列表而不是刪除和讀取?它會使您的方法中的代碼更簡單。 – clhereistian

回答

1

由於您正在測試的是與Items的交互,因此您將需要一個對象來測試,無論它是具體實例(如第二種方法)還是模擬。

如果您使用模擬,則需要將其設置爲在調用OfType時返回現有項目。然後,你可以明確地驗證到Remove進行呼叫,而不是檢查Count,像這樣(未測試):

Items.Verify(
    x => x.Remove(
     It.Is<Item>(
      item => item.Key == itemKey))); 

說到這裏,我不禁想,這個功能應該可以封裝在Cart,而不暴露Item列表在該類之外進行操作。這將使寫測試變得更容易。

1

當使用模擬(例如Mock<Cart>)進行測試時,您正在測試您的代碼如何與嘲笑交互。當使用真實對象進行測試時(例如Cart),您正在測試最終結果

所以在失敗的測試中,因爲您使用的是模擬遊戲,因此您需要測試模擬遊戲的互動方式。因此,你想測試你的代碼是正確調用Remove方法:

cart.Verify(x => x.Remove(It.IsAny<Item>())); 

這並不好,因爲它可以爲你要更換It.IsAny<Item>()與實際預期的項目。這只是意味着你必須設置一個模擬的項目清單太:

var itemsListMock = new Mock<List<Item>>(); 
    cart.SetupGet(m => m.Items).Returns(itemsListMock.Object); 
    //TODO setup getting 'duplicates' from Where clause 

希望這是一種明確而有意義。