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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11135337/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 16:38:34  来源:igfitidea点击:

XUnit Assertion for checking equality of objects

c#xunit.netxunit

提问by inquisitive

I am using XUnit framework to test my C# code.

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

Is there any assert method available in this framework which does the object comparison? My intention is to check for equality of each of the object's public and private member variables.

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

I tried those alternatives but seldom it works:

我尝试了这些替代方案,但很少奏效:

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

采纳答案by Baz1nga

You need to have a custom comparer to achieve this, when you compare objects otherwise they are checked on the basis of whether they are referring to the same object in memory. To override this behavior you need to override the Equalsand GetHashCodemethod and then you could do:

您需要有一个自定义比较器来实现这一点,当您比较对象时,否则会根据它们是否引用内存中的同一对象来检查它们。要覆盖此行为,您需要覆盖EqualsandGetHashCode方法,然后您可以执行以下操作:

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

Here is an MSDN page abt overloading Equals method: http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx

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

Also apt the comment on the question: What's the difference between IEquatable and just overriding Object.Equals()?

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

回答by The Integrator

I had similar issue, but then luckily I am already using

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

using Newtonsoft.Json;

So I just had to serialize it to json object then compare as string.

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

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

回答by Engineer_Andrew

I know this is an old question, but since I stumbled upon it I figured I'd weigh in with a new solution that's available (at least in xunit 2.3.1 in a .net Core 2.0 solution).

我知道这是一个老问题,但由于我偶然发现了它,我想我会考虑一个可用的新解决方案(至少在 .net Core 2.0 解决方案中的 xunit 2.3.1 中)。

I'm not sure when it was introduced, but there is now an overloaded form of .Equalthat accepts an instance of IEqualityComparer<T>as the third parameter. You can create a custom comparer in your unit test without polluting your code with it.

我不确定它是什么时候引入的,但现在有一个重载形式,.Equal它接受一个实例IEqualityComparer<T>作为第三个参数。您可以在单元测试中创建自定义比较器,而不会用它污染您的代码。

The following code can be invoked like this: Assert.Equal(expectedParameters, parameters, new CustomComparer<ParameterValue>());

可以像这样调用以下代码: Assert.Equal(expectedParameters, parameters, new CustomComparer<ParameterValue>());

XUnit natively appears to stop processing a test as soon as a failure is encountered, so throwing a new EqualExceptionfrom within our comparer seems to be in line with how XUnit works out of the box.

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

Edit: I found that comparing the actual and expected values with !=was not effective for certain types (I'm sure there's a better explanation involving the difference between reference types and value types, but that's not for today). I updated the code to use the .Equalsmethod to compare the two values and that seems to work much better.

编辑:我发现比较实际值和预期值!=对某些类型无效(我确定有更好的解释涉及引用类型和值类型之间的差异,但这不适用于今天)。我更新了代码以使用该.Equals方法来比较两个值,这似乎效果更好。

回答by maracuja-juice

There are NuGet packages that do this for you. Here are two examples that I personally use.

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

回答by Adrian Petrescu

FluentAssertionslibrary has some pretty powerful comparison logic inside.

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

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

You can even use this to assert on part of "myObject". However, it might not help you with the private fields.

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