流利的断言;结合集合和对象图比较断言

FluentAssertions; combining collection and object graph comparison assertions

我正在尝试使用 FluentAssertions 来组合集合和对象图比较断言。

我有以下 class.

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

你可以覆盖你的合同 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);
    }
}

如您所见,它通过了测试:

据我从文档和我使用该框架的经验来看,它确实使用了 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");
}

作为 Nkosi's 答案的替代方案,您仍然可以通过构建期望来使用 ShouldBeEquivalentTo