单元测试 - 当您的代码几乎只是一个计算(例如 GetHashCode)时,您会做什么?

发布于 2024-11-19 16:13:55 字数 1028 浏览 2 评论 0原文

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);
}

或者还有其他方法吗?

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();
    }
}

When you go to Unit Test the GetHashCode, I'm torn between calculating the original components and repeating the function or using a predetermined value:

[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);
}

Or is there some other way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

黎歌 2024-11-26 16:13:55

单元测试是为了测试逻辑。 GetHashCode 计算本身符合逻辑吗?事实并非如此,尽管意见可能有所不同。

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

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

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

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

您的两个示例测试都非常脆弱,并且完全有效的 GetHashCode 实现将使它们失败。回想一下,单元测试的主要目的之一是让重构无所畏惧。但是,没有人可以在不破坏单元测试的情况下重构 GetHashCode

Unit testing is for testing logic. Is the GetHashCode calculation itself logic? Not really, although opinions may vary.

The relevant logic here is that two objects that are equal have the same hash code, i.e. Equals and HashCode are compatible. Or, quoting from the docs:

  • If two objects compare as equal, the GetHashCode method for each object must return the same value. However, if two objects do not compare as equal, the GetHashCode methods for the two object do not have to return different values.

  • The GetHashCode method for an object must consistently return the same hash code as long as there is no modification to the object state that determines the return value of the object's Equals method. Note that this is true only for the current execution of an application, and that a different hash code can be returned if the application is run again.

So I would write unit tests that guarantee that those conditions are met, not that the internal implementation of GetHashCode matches a predetermined procedure.

Both of your example tests are highly brittle, and perfectly valid GetHashCode implementations would fail them. Recall that one of the major purposes of unit tests is to allow refactoring without fear. But, nobody can refactor GetHashCode without your unit tests breaking.

别把无礼当个性 2024-11-26 16:13:55

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

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

示例条件:

  • 生成的哈希值有限制吗?最小值、最大值、奇数、偶数等。
  • 它是否正确散列正数和负数?
  • 它是否在适当的条件下创造独特的价值?

I compare the result against pre-computed values with lots of commenting to explain why I chose the values being tested.

For pure calculations, I tend to write unit tests so that they ensure the function keeps the conditions that are required/expected of the code that will use it.

Example conditions:

  • Are there any constraints on the generated hash value? min value, max value, odd, even, etc.
  • Does it properly hash positive and negative numbers?
  • Does it create unique values under the appropriate conditions?
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文