Утверждение XUnit для проверки равенства объектов

Я использую фреймворк XUnit для проверки кода на С#.

Есть ли какой-либо метод assert, доступный в этой структуре, который выполняет сравнение объектов? Мое намерение - проверить равенство каждой из публичных и частных переменных объекта.

Я пробовал эти альтернативы, но редко он работает:

1) bool IsEqual = (Obj1 == Obj2)
2) Assert.Same(Obj1, Obj2) which I couldnt understand what happens internally

Ответ 1

Для этого вам нужно иметь собственный компаратор, когда вы сравниваете объекты, в противном случае они проверяются на основании того, ссылаются ли они на один и тот же объект в памяти. Чтобы переопределить это поведение, вам нужно переопределить метод Equals и GetHashCode, а затем вы можете сделать следующее:

Assert.True(obj1.Equals(obj2));

Вот страница MSDN с перегрузкой методом Equals: http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx

Также добавьте комментарий к вопросу: В чем разница между IEquatable и просто переопределением Object.Equals()?

Ответ 2

У меня была аналогичная проблема, но, к счастью, я уже использую

using Newtonsoft.Json;

Поэтому мне просто пришлось сериализовать его на json-объект, а затем сравнить как строку.

var obj1Str = JsonConvert.SerializeObject(obj1);
var obj2Str = JsonConvert.SerializeObject(obj2);
Assert.Equal(obj1Str, obj2Str );

Ответ 3

Есть пакеты NuGet, которые делают это для вас. Вот два примера, которые я лично использую.

  1. DeepEqual:

    object1.ShouldDeepEqual(object2);
    
  2. ExpectedObjects:

    [Fact]
    public void RetrievingACustomer_ShouldReturnTheExpectedCustomer()
    {
      // Arrange
      var expectedCustomer = new Customer
      {
        FirstName = "Silence",
        LastName = "Dogood",
        Address = new Address
        {
          AddressLineOne = "The New-England Courant",
          AddressLineTwo = "3 Queen Street",
          City = "Boston",
          State = "MA",
          PostalCode = "02114"
        }                                            
      }.ToExpectedObject();
    
    
      // Act
      var actualCustomer = new CustomerService().GetCustomerByName("Silence", "Dogood");
    
      // Assert
      expectedCustomer.ShouldEqual(actualCustomer);
    }
    

Ответ 4

Я знаю, что это старый вопрос, но с тех пор, как я наткнулся на него, я решил взвесить новое доступное решение (по крайней мере, в xunit 2.3.1 в решении .net Core 2.0).

Я не уверен, когда он был представлен, но теперь есть перегруженная форма .Equal, которая принимает экземпляр IEqualityComparer<T> в качестве третьего параметра. Вы можете создать собственный компаратор в своем модульном тесте, не загрязняя при этом свой код.

Следующий код может быть вызван так: Assert.Equal(expectedParameters, parameters, new CustomComparer<ParameterValue>());

XUnit, по-видимому, изначально останавливает обработку теста, как только обнаруживается сбой, поэтому добавление нового EqualException из нашего компаратора похоже соответствует тому, как XUnit работает из коробки.

public class CustomComparer<T> : IEqualityComparer<T>
{
    public bool Equals(T expected, T actual)
    {
        var props = typeof(T).GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
        foreach (var prop in props)
        {
            var expectedValue = prop.GetValue(expected, null);
            var actualValue = prop.GetValue(actual, null);
            if (!expectedValue.Equals(actualValue))
            {
                throw new EqualException($"A value of \"{expectedValue}\" for property \"{prop.Name}\"",
                    $"A value of \"{actualValue}\" for property \"{prop.Name}\"");
            }
        }

        return true;
    }

    public int GetHashCode(T parameterValue)
    {
        return Tuple.Create(parameterValue).GetHashCode();
    }
}

Изменение: я обнаружил, что сравнение фактических и ожидаемых значений с != неэффективно для определенных типов (я уверен, что есть лучшее объяснение, связанное с разницей между ссылочными типами и типами значений, но не на сегодня). Я обновил код, чтобы использовать метод .Equals для сравнения двух значений, и это, кажется, работает намного лучше.

Ответ 5

В библиотеке FluentAssertions есть довольно мощная логика сравнения.

myObject.ShouldBeEquivalentTo(new { SomeProperty = "abc", SomeOtherProperty = 23 });

Вы даже можете использовать это для подтверждения части "myObject". Тем не менее, это может не помочь вам с частными полями.