繁体   English   中英

为HashCode方法创建单元测试

[英]Create an unit test for an HashCode method

我有以下HashCode助手:

public struct HashCode {

  private readonly Int32 Value;

  private HashCode(Int32 value) {
    Value = value;
  }

  public static implicit operator Int32(HashCode hashCode) {
    return hashCode.Value;
  }

  public static HashCode Of<T>(T item) {
    return new HashCode(GetHashCode(item));
  }

  public HashCode And<T>(T item) {
    return new HashCode(CombineHashCodes(Value, GetHashCode(item)));
  }

  public HashCode AndEach<T>(IEnumerable<T> items) {      
    Int32 hashCode = items.Select(x => GetHashCode(x)).Aggregate((x, y) => CombineHashCodes(x, y));
    return new HashCode(CombineHashCodes(Value, hashCode));
  }

  private static Int32 CombineHashCodes(Int32 x, Int32 y) {

    // Taken from:
    https://github.com/dotnet/coreclr/blob/775003a4c72f0acc37eab84628fcef541533ba4e/src/mscorlib/src/System/Tuple.cs#L56

    unchecked {        
      return ((x << 5) + x) ^ y;
    }
  }

  private static Int32 GetHashCode<T>(T item) {
    return item == null ? 0 : item.GetHashCode();
  }

}

我使用它如下:

HashCode.Of(value1).And(value2).AndEach(collection);

我应该如何创建一个单元测试来测试此HashCode?

创建一个或两个已经对HashCode进行了硬编码的类,然后根据要使用多少粒度的单元测试来创建一个/多个测试,这些测试使用您的助手来计算哈希码:

var result = HashCode
  .Of(new HardcodedHashCode(5))
  .And(new HardcodedHashCode(1));

Assert.Equals(result, manually_computed_value);

对于HashCode助手的每次使用,您都必须手动计算预期的哈希码。 我建议对OfAndAndEach一次测试,再加上一个使用所有测试的测试。

编辑更多代码:

public class HardcodedHashCode {
  private readonly int _hashCode;

    public HardcodedHashCode(int hashCode) { _hashCode = hashCode; }

    public override int GetHashCode() => _hashCode; 
}

// example test
public void and_combines_hashcodes_using_xyz_method() {
   var h1 = new HardcodedHashCode(1);
   var h5 = new HardcodedHashCode(5);

   int combinedHashcode = HashCode.of(h1).And(h5);

   // sorry but can't force myself to compute manually in the evening
   Assert.Equals(_manually_compute_value_here_, combinedHashcode);
}

我应该警告您,您可能会尝试不正确地使用GetHashCode方法。 您正在将.NET哈希与自己的哈希混合在一起。 而且我想您的哈希与.NET哈希具有不同的目标。

首先,我应该提到,每个.NET对象都有其自己的哈希码,并且在创建对象后不应更改它。

object[] data = new object[] { 1, new Random(), 5 }; int hash1 = HashCode.AndEach(data); data[2] = "123"; int hash2 = HashCode.AndEach(data);

我假设hash1!= hash2。 对于.NET哈希,它会失败

这就是为什么您的HashCode.GetHashCode实现与任何延迟执行(例如Linq)相结合可以产生非常有趣的结果的原因。

此外,还有Microsoft文档 ,其中说:

哈希码用于在基于哈希表的集合中进行有效的插入和查找。 哈希码不是永久值

...

  • 不要序列化哈希码值或将其存储在数据库中。

例如,.NET CLR 2.0和.NET CLR 4.5中Object.GetHashCode的实现是不同的。 因此,如果您在测试中添加任何使用Object.GetHashCode方法的对象,则在.NET 2.0和.NET 4.5中单元测试结果可能会有所不同。

如果覆盖GetHashCode方法,则还应该覆盖Equals,反之亦然。

因此,通过csharpfolk提供的代码是不是类完全正确HardcodedHashCode 如果两个对象相等,则它们的哈希码必须相等(来自哈希定义)。 HardcodedHashCode应该重写Equals方法,否则有人可以创建单元测试,这对于.NET哈希是错误的。

因此,我建议从您的代码中消除对Object.GetHashCode任何调用。 或确保您的代码不违反Microsoft的准则。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM