2016-06-17 63 views
1

我想使用FluentAssertions結合集合和對象圖比較斷言。FluentAssertions;結合集合和對象圖比較斷言

我有以下類。

public class Contract 
{ 
    public Guid Id { get; set; } 
    public string Name { get; set; } 
} 

哪些返回集合中,就像這樣。

ICollection<Contract> contracts = factory.BuildContracts(); 

我再想確保集合只包含特定Contract對象。

contracts.Should().Contain(new Contract() { Id = id1, Name = "A" }); 

這是不行的,我相信,因爲Contain使用object.Equals而不是對象圖相比,(由ShouldBeEquivalentTo提供)。

我還需要斷言集合不包含特定對象,即

contracts.Should().NotContain(new Contract() { Id = id2, Name = "B" }); 

有效送達包含未知數量的項目的集合,我要保證;它包含許多特定的項目,並且它不包含許多特定的項目。

這可以使用FluentAssertions提供的函數來實現嗎?

作爲一個方面說明,我不想覆蓋object.Equals由於這裏討論的原因。 Should I be using IEquatable to ease testing of factories?

回答

2

它使用object.Equals據我可以從文檔和我的經驗告訴使用框架。

在這種情況下,我傾向於使用表達式謂詞,如the collections documentation for v3.0 and higher中引用的那樣。

以下示例說明如何確保集合只包含特定的Contract對象,並聲明該集合不包含特定的對象。

[TestMethod] 
public void FluentAssertions_Should_Validate_Collections() { 
    //Arrange 
    var id1 = Guid.NewGuid(); 
    var id2 = Guid.NewGuid(); 

    var list = new List<Contract>{ 
     new Contract() { Id = id1, Name = "A" }, 
     new Contract() { Id = Guid.NewGuid(), Name = "B"} 
    }; 

    var factoryMock = new Mock<IContractFactory>(); 
    factoryMock.Setup(m => m.BuildContracts()).Returns(list); 
    var factory = factoryMock.Object; 

    //Act 
    var contracts = factory.BuildContracts(); 

    //Assert 
    contracts.Should() 
     .HaveCount(list.Count) 
     .And.Contain(c => c.Id == id1 && c.Name == "A") 
     .And.NotContain(c => c.Id == id2 && c.Name == "B"); 
} 
1

您可以覆蓋您的合同Equals然後將使用它,並且您的單元測試應該愉快地通過。 如果你使用的是隨機Guids,它可能是一個問題,但它好像你正在使用預定義的。

給下面的一個嘗試:

protected bool Equals(Contract other) 
{ 
    return Id.Equals(other.Id) && string.Equals(Name, other.Name); 
} 

public override bool Equals(object obj) 
{ 
    if (ReferenceEquals(null, obj)) return false; 
    if (ReferenceEquals(this, obj)) return true; 
    if (obj.GetType() != this.GetType()) return false; 
    return Equals((Contract) obj); 
} 

public override int GetHashCode() 
{ 
    unchecked 
    { 
     return (Id.GetHashCode()*397)^(Name != null ? Name.GetHashCode() : 0); 
    } 
} 

,正如你所看到的,它通過測試: enter image description here

+0

+1並感謝您的建議。然而,這不是我想要的答案,我用來覆蓋equals,只是使用標準的'Assert.IsTrue(contracts.Contains(...))'。但是這有它自己的問題(http://stackoverflow.com/questions/33988487/should-i-be-using-iequatable-to-ease-testing-of-factories)。我希望使用FluentAssertions來避免重寫Equals。 –

+1

有趣的鏈接...我相信你會弄清楚什麼。我會密切關注帖子,看看它是如何演變的:)。順便說一句,你有沒有給「[應該](https://github.com/shouldly/shouldly)」跑步?我不確定它的默認行爲是什麼,但它可能以您想要的方式工作。 – Noctis

1

或者到Nkosi's答案,你仍然可以通過建立expecation使用ShouldBeEquivalentTo

+0

你的意思是像'Should()。Contain(c => c.ShouldBeEquivalentTo(contract1))'?不知道如何讓「ShouldBeEquivalentTo」沒有返回值。不完全是你「建設期望」的意思。謝謝 –

+0

只需按照您期望的那樣使用'Contract'實例創建一個集合,並將其作爲期望傳遞給'ShouldBeEquivalentTo'。如果你關心嚴格的訂單,甚至可以使用'options => options.WithStrictOrdering'' –

+0

如果集合包含其他'我不關心的'Contracts',那麼怎麼辦?即該集合包含100個項目,我想確保它包含2個特定項目,並且不包含1個特定項目。 –