测试Equals
方法相对来说比较直观(据我所知)。但是,如何测试GetHashCode
方法呢?
测试Equals
方法相对来说比较直观(据我所知)。但是,如何测试GetHashCode
方法呢?
测试两个相等的不同对象是否具有相同的哈希码(对于各种值)。逐个改变一个方面/属性,检查不相等的对象是否给出不同的哈希码。虽然哈希码不一定需要不同,但是除非存在错误,否则选择在 恰好 给出相同哈希码的属性上选择不同值非常不幸。
Gallio/MbUnit v3.2提供了方便的合约验证器,可以测试您对GetHashCode()
和IEquatable<T>
的实现。具体来说,您可能会对EqualityContract
和HashCodeAcceptanceContract
感兴趣。有关更多详细信息,请参见此处,此处以及那里。
public class Spot
{
private readonly int x;
private readonly int y;
public Spot(int x, int y)
{
this.x = x;
this.y = y;
}
public override int GetHashCode()
{
int h = -2128831035;
h = (h * 16777619) ^ x;
h = (h * 16777619) ^ y;
return h;
}
}
然后您可以像这样声明您的合约验证器:[TestFixture]
public class SpotTest
{
[VerifyContract]
public readonly IContract HashCodeAcceptanceTests = new HashCodeAcceptanceContract<Spot>()
{
CollisionProbabilityLimit = CollisionProbability.VeryLow,
UniformDistributionQuality = UniformDistributionQuality.Excellent,
DistinctInstances = DataGenerators.Join(Enumerable.Range(0, 1000), Enumerable.Range(0, 1000)).Select(o => new Spot(o.First, o.Second))
};
}
它与Equals()函数相似。你需要确保两个对象至少具有相同的哈希码,才能视为“相同”。这意味着如果.Equals()返回true,则哈希码也应该相同。至于正确的哈希码值是什么,这取决于你如何进行哈希。
根据个人经验,除了像相同对象会给你相同的哈希码这样显而易见的事情之外,您需要创建足够大的独特对象数组,并计算其中的唯一哈希码数量。如果唯一哈希码少于总对象数的50%,则表示您的哈希函数存在问题。
List<int> hashList = new List<int>(testObjectList.Count);
for (int i = 0; i < testObjectList.Count; i++)
{
hashList.Add(testObjectList[i]);
}
hashList.Sort();
int differentValues = 0;
int curValue = hashList[0];
for (int i = 1; i < hashList.Count; i++)
{
if (hashList[i] != curValue)
{
differentValues++;
curValue = hashList[i];
}
}
Assert.Greater(differentValues, hashList.Count/2);
您可以创建具有相同值的单独实例,并检查实例的 GetHashCode 是否返回相同的值,以及对同一实例进行重复调用是否返回相同的值。
这是哈希码工作的唯一要求。当然,为了良好地工作,哈希码应该具有良好的分布,但测试需要大量的测试...