Подтвердить что ты не робот

С#: Как бы вы unit test GetHashCode?

Тестирование метода Equals довольно прямолинейно (насколько я знаю). Но как вы протестируете метод GetHashCode?

4b9b3361

Ответ 1

Проверьте, что два разных одинаковых объекта имеют одинаковый хэш-код (для разных значений). Убедитесь, что неравные объекты предоставляют разные хеш-коды, изменяя один аспект/свойство за раз. В то время как хеш-коды не должны быть разными, вам действительно не повезло бы выбирать разные значения свойств, которые бы дали один и тот же хеш-код, если у вас нет ошибки.

Ответ 2

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

Ответ 3

Это было бы довольно похоже на Equals(). Вы хотите убедиться, что два объекта, которые были "одинаковыми", по крайней мере имели одинаковый хеш-код. Это означает, что если .Equals() возвращает true, хэш-коды также должны быть идентичными. Что касается правильных значений хэш-кода, это зависит от того, как вы хешируете.

Ответ 4

Из личного опыта. Помимо очевидных вещей, подобных тем же объектам, которые дают вам одинаковые хеш-коды, вам нужно создать достаточно большой массив уникальных объектов и подсчитать уникальные хэш-коды среди них. Если уникальные хеш-коды составляют меньше, например, 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);

Ответ 5

Я бы предварительно поставил известный/ожидаемый хеш и сравнил результат GetHashCode.

Ответ 6

Вы создаете отдельные экземпляры с тем же значением и проверяете, что GetHashCode для экземпляров возвращает одно и то же значение, а повторные вызовы одного экземпляра возвращают одно и то же значение.

Это единственное требование для работы хеш-кода. Чтобы хорошо работать, хэш-коды должны, конечно, иметь хорошее распространение, но для тестирования для этого требуется много тестов...

Ответ 7

В дополнение к проверке того, что равенство объектов подразумевает равенство хэш-кодов, а распределение хэшей довольно плоское, как предложил Янн Тревин (если производительность является проблемой), вы также можете рассмотреть, что произойдет, если вы измените свойство объект.

Предположим, что ваш объект изменяется, когда он находится в словаре /hashset. Вы хотите, чтобы Contains (object) все еще был правдой? Если это так, то ваш GetHashCode лучше не зависит от измененного свойства, которое было изменено.