单元测试:克隆和相等

本文关键字:单元测试 | 更新日期: 2023-09-27 18:07:14

我正在编写单元测试,并考虑实现IClonable的类型的场景。当然,我想要一个测试Clone()方法的单元测试。

[Test]
public void CloneObject()
{
    MyType original = new MyType();
    MyType clone = (MyType)original.Clone();
    // Assert for equality
}

所以我的第一个任务是得到等式的Assert。我看到以下选项:

  • 遍历MyType的所有属性(字段)并逐一检查
  • 重写MyType中的Equals(),让MyType表示两个实例是否相等(考虑到有时测试代码的相等性被认为与生产代码的相等性不同)
  • 如果实例相等,检查某种序列化(在这种情况下,MyType必须是[Serializable],但有时很难做到,如果它有接口属性)
  • …? ?

对于前两个,我可以设置我的测试,它们工作得很好。但是如果我改变MyType并添加一个额外的属性呢?如果Clone()不复制这个,我没有将它添加到检查属性或equals方法的列表中,即使属性没有被复制,我的测试仍然通过。

你如何解决这类测试?

单元测试:克隆和相等

你可以使用FluentAssertions库(一个TDD必须有,IMO),它有一个ShouldBeEquivalent方法,执行两个对象的图形比较:

original.ShouldBeEquivalentTo(clone);

比较算法可通过可选的options参数自定义;查看他们的wiki获取详细信息。

为了使测试能够适应未来(即,当新属性被添加到类中,但不是添加到Clone方法时,它会中断),您可能想要测试克隆一个对象,并将其所有属性设置为随机的非默认值。AutoFixture可以为你做这些。

// Arrange
var fixture = new Fixture();
var original = fixture.Create<MyType>();
// Act
var clone = original.Clone();
// Assert
clone.ShouldBeEquivalentTo(original);

的有用链接:

  • FluentAssertions小抄
  • AutoFixture备忘单(它有点过时,但它展示了它的大多数基本功能)

我倾向于实现Equals()。我看不出为什么Equals()需要在生产和测试中产生不同的结果。

如果你不这样做,你的Assert可以调用object.ReferenceEquals(),如下所示:

Assert.IsTrue(object.ReferenceEquals(expectedObject, objectInHand));