流利的断言;结合集合和对象图比较断言
Posted
技术标签:
【中文标题】流利的断言;结合集合和对象图比较断言【英文标题】:FluentAssertions; combining collection and object graph comparison assertions 【发布时间】:2016-10-19 10:32:09 【问题描述】:我正在尝试使用 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?
【问题讨论】:
【参考方案1】:据我从文档和我使用框架的经验来看,它确实使用了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");
【讨论】:
【参考方案2】:您可以覆盖您的合同Equals
,然后将使用该合同,您的单元测试应该会顺利通过。
如果您使用的是随机 Guid,这可能是个问题,但您似乎使用的是预定义的。
尝试以下方法:
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);
如您所见,它通过了测试:
【讨论】:
+1 并感谢您的建议。然而,这并不是我真正想要的答案,我曾经重写 equals 并只使用标准的Assert.IsTrue(contracts.Contains(...))
。但这有其自身的问题(***.com/questions/33988487/…)。我希望使用 FluentAssertions 来避免覆盖 Equals。
有趣的链接...我相信你会想出办法的。我会密切关注这个帖子,看看它是如何演变的:)。顺便说一句,你给“shouldly”跑了吗?我不确定它的默认行为是什么,但它可能会按照你想要的方式工作。【参考方案3】:
除了Nkosi's 答案,您仍然可以通过构建期望来使用ShouldBeEquivalentTo
。
【讨论】:
你的意思是像Should().Contain(c => c.ShouldBeEquivalentTo(contract1))
吗?不知道如何让它工作,因为ShouldBeEquivalentTo
没有返回值。不完全是您所说的“建立期望”。谢谢
只需按照您的期望使用Contract
实例创建一个集合,并将其作为期望传递给ShouldBeEquivalentTo
。如果您关心严格的顺序,您甚至可以使用options => options.WithStrictOrdering
'
如果集合中包含其他我不关心的Contracts
怎么办? IE。该集合包含 100 个项目,我想确保它包含 2 个特定项目,并且不包含 1 个特定项目。以上是关于流利的断言;结合集合和对象图比较断言的主要内容,如果未能解决你的问题,请参考以下文章