Сравнение объектов в модульном тестировании - PullRequest
13 голосов
/ 05 февраля 2010

У меня есть два объекта в моем модульном тесте, фактический и ожидаемый объект. Все свойства метода объекта абсолютно одинаковы, и если я выполню следующий тест:

Assert.AreEqual( expectedObject.Property1, actualObject.Property1);

результат проходит как положено. Однако, когда я пытаюсь запустить следующий тест, он терпит неудачу:

Assert.AreEqual (expectedObject, actualObject);

Чего мне не хватает? Можно ли сравнивать два объекта и нужно ли проверять каждое свойство?

Ответы [ 7 ]

15 голосов
/ 05 февраля 2010

Вам нужно переопределить Equals для вашего объекта. Assert использует Object.Equals. По умолчанию Object.Equals для объектов ссылочного типа выполняет сравнение ссылок. То есть два экземпляра ссылочного типа равны тогда и только тогда, когда они ссылаются на один и тот же объект. Вы хотите переопределить это, чтобы вместо сравнения ссылок было выполнено сравнение значений. Вот очень хорошая MSDN статья на эту тему. Обратите внимание, что вам также нужно переопределить GetHashCode. См. MSDN для рекомендаций . Вот простой пример:

До:

class Test {
    public int Value { get; set; }
}

Test first = new Test { Value = 17 };
Test second = new Test { Value = 17 };
Console.WriteLine(first.Equals(second)); // false

После того, как:

class Test {
    public int Value { get; set; }
    public override bool Equals(object obj) {
        Test other = obj as Test;
        if(other == null) {
            return false; 
        }
        return this.Value == other.Value;
    }
    public override int GetHashCode() { 
        return this.Value.GetHashCode();
    }
}

Test first = new Test { Value = 17 };
Test second = new Test { Value = 17 };
Console.WriteLine(first.Equals(second)); // true
4 голосов
/ 05 февраля 2010

Второе утверждение assert фактически сравнивает ссылки объектов, а не содержимое. Поскольку параметры метода AreEqual относятся к типу объектов, информации о том, как их должен сравнивать каркас модульного теста, не так много.

РЕДАКТИРОВАТЬ: проверьте этот вопрос: Сравните равенство между двумя объектами в NUnit

1 голос
/ 19 декабря 2011

Это правда. Равны ли эти два объекта полностью или нет, зависит от реализации его метода Equals. Иногда с помощью метода Equal также полезно переопределить реализацию GetHashCode. Если это не переопределение, виртуальная реализация по умолчанию (класса Object) будет рассматриваться вместе с оценкой метода Equal. Чтобы объект считался равным, его хеш-код должен быть одинаковым.

Однако для модульного теста я бы посоветовал не сильно полагаться на реализацию метода Equal. Независимо от того, какое свойство вы хотите установить, сравните эти свойства объекта самостоятельно, потому что снова метод Equal может быть пользовательской реализацией, поэтому есть вероятность, что он может содержать ошибки в конце дня. Поэтому лучше доверять методу Equal, определенному системой, для модульного тестирования.

1 голос
/ 05 февраля 2010

Вы не можете использовать знак '=', если не перегрузили его на свой объект. В вашем объектном классе вам нужно сделать что-то вроде:


public override bool Equals(object obj)
{
   if(obj == null)
      return false;
   return (this.Property1 == obj.Property1 && 
          this.Property2 == obj.Property2);
}

Если вы этого не сделаете, вы просто сравниваете ссылки на объекты.

0 голосов
/ 07 октября 2015

Это типичная эквивалентность проблема и похоже, что принятый ответ не является хорошим.Я попытаюсь объяснить, почему.

Представьте себе следующее - вы должны написать интеграционный тест на своем бэкэнде, чтобы убедиться, что он правильно сохраняет ваш объект домена.У вас есть код:

[TestMethod]
    [Description(@"Sequentially perform operations
                 1. Save new item in DB
                 2. Get same Item from DB
                 Ensure that saved and get Items are equivalent")]
    public void Repository_Create_Test()
    {
        var initialItem = GetTestItem();
        //create item and check it is created correct
        initialItem.ID = repository.Create(initialItem, userID, ownerID);
        Item resultItem = repository.GetById(initialItem.ID, ownerID);
        resultItem.Should().NotBeNull();
        Assert.AreEqual(initialItem, resultItem);
    }

Итак, вам нужно убедиться, что считанный из хранилища объект является абсолютным эквивалентом объекта, который мы отправили в хранилище.Переопределение Equals здесь легко догадаться.Для этого случая нам нужно настроить Equals, чтобы сравнить все поля объектов.Но с точки зрения DDD это просто неправильно.Доменные сущности различаются по неизменяемому ключу (или первичному ключу), а не по всем изменяемым полям.Итак, если мы моделируем HR-домен, и у гипотетического «Мистера Икс» появился новый номер телефона, он все равно остается тем же «Мистером Икс».

Все это говорит о том, что в настоящее время я использую FluentAssertions Framework, который обладает довольно мощным средством проверки эквивалентности.Как это:

resultItem.ShouldBeEquivalentTo(initialItem);
0 голосов
/ 07 марта 2015

https://github.com/kbilsted/StatePrinter был написан специально для вывода графов объектов в строковое представление с целью написания простых модульных тестов.

  • Он поставляется с методами Assert, которые выводят правильно экранированную строку, легко копируют и вставляют в тест для ее исправления.
  • Позволяет автоматически переписать unittest
  • Интегрируется со всеми платформами модульного тестирования
  • В отличие от сериализации JSON поддерживаются циклические ссылки
  • Вы можете легко фильтровать, так что сбрасываются только части типов

Учитывая

class A
{
  public DateTime X;
  public DateTime Y { get; set; }
  public string Name;
}

Вы можете в безопасном виде и с помощью автозаполнения Visual Studio включать или исключать поля.

  var printer = new Stateprinter();
  printer.Configuration.Projectionharvester().Exclude<A>(x => x.X, x => x.Y);

  var sut = new A { X = DateTime.Now, Name = "Charly" };

  var expected = @"new A(){ Name = ""Charly""}";
  printer.Assert.PrintIsSame(expected, sut);
0 голосов
/ 19 декабря 2011

Дипак: Это значит, что в конце дня я не буду сравнивать объекты. Сравните значение свойств объекта. Правильно ... Этот метод равного переопределения предназначен только для конкретного объекта ... Это ограничение не является правильным ...

Вот хорошая ссылка ... Перед подготовкой UnitTest создайте свой собственный класс для справки по тестированию

http://manfred -ramoser.blogspot.com / 2007/11 / с-блок-тестирование-helper.html

...