用于检查对象相等性的 XUnit 断言

问题描述 投票:0回答:7

我正在使用 XUnit 框架来测试我的 C# 代码。

此框架中是否有可用的断言方法来进行对象比较?我的目的是检查每个对象的公共和私有成员变量是否相等。

我尝试了这些替代方案,但很少起作用:

1) bool IsEqual = (Obj1 == Obj2)
2) Assert.Same(Obj1, Obj2) which I couldnt understand what happens internally
c# xunit.net xunit
7个回答
106
投票

我有类似的问题,但幸运的是我已经在使用

using Newtonsoft.Json;

所以我只需将其序列化为 json 对象,然后作为字符串进行比较。

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

38
投票

FluentAssertions 库内部有一些非常强大的比较逻辑。

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

您甚至可以使用它来断言“myObject”的一部分。 但是,它可能对您的私有字段没有帮助。


34
投票

从 2022 年 8 月 1 日发布的 Xunit 2.4.2 开始,此功能作为 Assert.Equivalent 实现。

示例:

Assert.Equivalent(Obj1, Obj2);

Assert.Equivalent(Obj1, Obj2, strict:true)

请参阅发行说明:https://xunit.net/releases/v2/2.4.2


23
投票

您需要有一个自定义比较器来实现此目的,当您比较对象时,否则将根据它们是否引用内存中的同一对象来检查它们。要覆盖此行为,您需要覆盖

Equals
GetHashCode
方法,然后您可以执行以下操作:

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

这是一个关于重载 Equals 方法的 MSDN 页面:http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx

也适合这个问题的评论:IEquatable 和只是重写 Object.Equals() 之间有什么区别?


20
投票

有 NuGet 包可以为您执行此操作。 这是我个人使用的两个例子。

  1. 深平等

    object1.ShouldDeepEqual(object2);
    
  2. 预期对象:

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

10
投票

我知道这是一个老问题,但自从我偶然发现它以来,我想我应该权衡一个可用的新解决方案(至少在 .net Core 2.0 解决方案中的 xunit 2.3.1 中)。

我不确定它是什么时候引入的,但现在有一个

.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
方法来比较两个值,这似乎效果更好。


1
投票

这是 IEqualityComparer 接口的另一个实现,它具有真正的 GenericComparer

并且为了断言相同类型的 2 个列表相等,无论列表容器如何,您可以添加此扩展:

public static bool IsEqualTo<T>(this IEnumerable<T> list, IEnumerable<T> expected) where T : class
{
    if (!list.HasSameLengthThan<T>(expected))
        return false;

    Assert.Equal(expected, list, new GenericComparer<T>());
    return true;
}
© www.soinside.com 2019 - 2024. All rights reserved.