Утверждение 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, которые делают это для вас.
Вот два примера, которые я лично использую.
DeepEqual:
object1.ShouldDeepEqual(object2);
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".
Тем не менее, это может не помочь вам с частными полями.