单元测试——当你的代码几乎只是一个计算(例如GetHashCode)时,你该怎么做?

本文关键字:GetHashCode 例如 计算 一个 代码 单元测试 当你 | 更新日期: 2023-09-27 18:02:05

public class Foo
{
    public int X { get; set; }
    public int Y { get; set; }
    public int Z { get; set; }
    public override int GetHashCode()
    {
        var hash = 17;
        hash *= 23 + x.GetHashCode();
        hash *= 23 + y.GetHashCode();
        hash *= 23 + z.GetHashCode();
    }
}

当你去单元测试GetHashCode时,我在计算原始组件和重复函数或使用预定值之间犹豫不决:

[TestMethod]
public void Test1
{
    var x = 1; y = 2; z = 3;
    var foo = new Foo() { X = x, Y = y, Z = z };
    var hash = 17;
    hash *= 23 + x.GetHashCode();
    hash *= 23 + y.GetHashCode();
    hash *= 23 + z.GetHashCode();
    var expected = hash;
    var actual = foo.GetHashCode();
    Assert.AreEqual(expected, actual);
}
[TestMethod]
public void Test2
{
    var x = 1; y = 2; z = 3;
    var foo = new Foo() { X = x, Y = y, Z = z };
    var expected = ? //Some predetermined value (calculated by hand?)
    var actual = foo.GetHashCode();
    Assert.AreEqual(expected, actual);
}

还是有其他方法?

单元测试——当你的代码几乎只是一个计算(例如GetHashCode)时,你该怎么做?

单元测试是用于测试逻辑的。计算GetHashCode本身是否符合逻辑?不完全是,尽管意见可能各不相同。

相关的逻辑是两个相等的对象具有相同的哈希码,即EqualsHashCode是兼容的。或者,从文档中引用:

  • 如果两个对象比较相等,则每个对象的GetHashCode方法必须返回相同的值。但是,如果两个对象的比较结果不相等,则这两个对象的GetHashCode方法不必返回不同的值。

  • 对象的GetHashCode方法必须一致地返回相同的哈希码,只要没有修改对象的状态,确定对象的Equals方法的返回值。请注意,这只适用于应用程序的当前执行,如果再次运行应用程序,则可以返回不同的哈希码。

因此,我会编写单元测试来保证满足这些条件,而不是保证GetHashCode的内部实现匹配预定的过程。

您的两个示例测试都非常脆弱,完全有效的GetHashCode实现将无法通过它们。回想一下,单元测试的主要目的之一是允许重构而不必担心。但是,没有人可以重构GetHashCode而不破坏单元测试。

我将结果与预先计算的值进行比较,并使用大量注释来解释为什么我选择要测试的值。

对于纯计算,我倾向于编写单元测试,以确保函数保持使用它的代码所需/期望的条件。

例子条件:

  • 对生成的哈希值有任何约束吗?最小值、最大值、奇数、偶数等
  • 它是否正确地散列正数和负数?
  • 它是否在适当的条件下产生唯一的值?
相关文章: