比较NUnit中两个对象之间的相等性


126

我试图断言一个对象与另一个对象“相等”。

这些对象只是具有大量公共属性的类的实例。有一种简单的方法可以让NUnit根据属性声明相等性吗?

这是我目前的解决方案,但我认为可能会有更好的选择:

Assert.AreEqual(LeftObject.Property1, RightObject.Property1)
Assert.AreEqual(LeftObject.Property2, RightObject.Property2)
Assert.AreEqual(LeftObject.Property3, RightObject.Property3)
...
Assert.AreEqual(LeftObject.PropertyN, RightObject.PropertyN)

我要追求的是与CollectionEquivalentConstraint相同的精神,其中NUnit验证两个集合的内容相同。

Answers:


51

覆盖。等于对象,然后在单元测试中只需执行以下操作:

Assert.AreEqual(LeftObject, RightObject);

当然,这可能意味着您只需将所有单个比较都移至.Equals方法,但这将允许您将该实现重复用于多个测试,并且如果对象无论如何都应该能够将自己与同级进行比较,则可能有意义。


2
谢谢,lassevk。这对我有用!我根据此处的指南实施了.quals:msdn.microsoft.com/en-us/library/336aedhh
Michael Haren

12
和GetHashCode(),很明显;-p
Marc Gravell

该页面上列表的第一个数字是覆盖GetHashCode,他确实说他遵循了这些准则:)但是,是的,忽略这一点的常见错误。通常,大多数时候您不会注意到错误,但是当您这样做时,就像您说“哦,嘿,为什么这条蛇把我的裤子扎起来,为什么他咬我的屁股”时。
拉瑟五世卡尔森

1
一个重要的警告:如果您的对象也实现了IEnumerable该对象,则将其作为一个集合进行比较,而不管其覆盖的实现是什么,Equals因为NUnit的IEnumerable优先级更高。有关NUnitEqualityComparer.AreEqual详细信息,请参见方法。您可以使用相等约束的Using()一种方法来覆盖比较器。即使那样,IEqualityComparer由于NUnit使用的适配器,实现非泛型还是不够的。
Kaleb Pederson

13
更多警告:GetHashCode()如果您曾经使用该对象作为键,则对可变类型的实现会产生不良行为。恕我直言,覆盖Equals()GetHashCode()并使对象仅用于测试不可变是没有道理的。
bavaza 2013年

118

如果由于某种原因无法覆盖Equals,则可以构建一个帮助程序方法,该方法通过反射来遍历公共属性并声明每个属性。像这样:

public static class AssertEx
{
    public static void PropertyValuesAreEquals(object actual, object expected)
    {
        PropertyInfo[] properties = expected.GetType().GetProperties();
        foreach (PropertyInfo property in properties)
        {
            object expectedValue = property.GetValue(expected, null);
            object actualValue = property.GetValue(actual, null);

            if (actualValue is IList)
                AssertListsAreEquals(property, (IList)actualValue, (IList)expectedValue);
            else if (!Equals(expectedValue, actualValue))
                Assert.Fail("Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType.Name, property.Name, expectedValue, actualValue);
        }
    }

    private static void AssertListsAreEquals(PropertyInfo property, IList actualList, IList expectedList)
    {
        if (actualList.Count != expectedList.Count)
            Assert.Fail("Property {0}.{1} does not match. Expected IList containing {2} elements but was IList containing {3} elements", property.PropertyType.Name, property.Name, expectedList.Count, actualList.Count);

        for (int i = 0; i < actualList.Count; i++)
            if (!Equals(actualList[i], expectedList[i]))
                Assert.Fail("Property {0}.{1} does not match. Expected IList with element {1} equals to {2} but was IList with element {1} equals to {3}", property.PropertyType.Name, property.Name, expectedList[i], actualList[i]);
    }
}

@wesley:这是不正确的。Type.GetProperties方法:返回当前Type的所有公共属性。请参阅msdn.microsoft.com/en-us/library/aky14axb.aspx
Sergii Volchkov 2011年

4
谢谢。但是,我必须切换实际和预期参数的顺序,因为收敛是预期是实际参数之前的参数。
Valamas

这是一种更好的方法,恕我直言,Equal和HashCode重写不必一定基于比较每个字段,而且在每个对象上进行都非常繁琐。做得好!
斯科特·怀特

3
如果您的类型仅具有基本类型作为属性,则此方法非常有用。但是,如果您的类型具有带有自定义类型的属性(未实现Equals),它将失败。
鲍比·坎农

为对象属性添加了一些递归,但是我不得不跳过了索引属性:
cerhart 2013年

113

不要仅出于测试目的而覆盖Equals。这很繁琐,并且会影响域逻辑。代替,

使用JSON比较对象的数据

您的对象上没有其他逻辑。没有额外的测试任务。

只需使用以下简单方法:

public static void AreEqualByJson(object expected, object actual)
{
    var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
    var expectedJson = serializer.Serialize(expected);
    var actualJson = serializer.Serialize(actual);
    Assert.AreEqual(expectedJson, actualJson);
}

看起来效果很好。测试运行程序结果信息将显示包含的JSON字符串比较(对象图),因此您可以直接看到问题所在。

另请注意!如果您有较大的复杂对象,并且只想比较它们的一部分,则可以(使用LINQ进行序列数据)创建匿名对象以与上述方法一起使用。

public void SomeTest()
{
    var expect = new { PropA = 12, PropB = 14 };
    var sut = loc.Resolve<SomeSvc>();
    var bigObjectResult = sut.Execute(); // This will return a big object with loads of properties 
    AssExt.AreEqualByJson(expect, new { bigObjectResult.PropA, bigObjectResult.PropB });
}

1
这是一种很好的测试方法,尤其是如果您仍在处理JSON(例如,使用类型化的客户端访问Web服务)时。这个答案应该更高。
Roopesh Shenoy

1
使用Linq!@DmitryBLR(见在回答最后一段):)
马克斯

3
这是一个好主意。我将使用较新的Json.NET:var ExpectedJson = Newtonsoft.Json.JsonConvert.SerializeObject(expected);
BrokeMyLegBiking

2
这不适用于循环引用。请改用github.com/kbilsted/StatePrinter来改善JSON方法的使用体验
Carlo V. Dango

2
@KokaChernov是正确的,有时您想通过顺序不相同的测试失败,但是如果您不想通过顺序不相同的测试失败,则可以在将列表传递给AreEqualByJson方法之前对列表进行显式排序(使用linq)。答案中的最后一个代码示例是在测试之前“重新排列”对象的简单变体。因此,我认为这非常“普遍”!:)
最大

91

尝试FluentAssertions库:

dto.ShouldHave(). AllProperties().EqualTo(customer);

http://www.fluentassertions.com/

也可以使用NuGet进行安装。


18
应该已弃用,因此应该是dto.ShouldBeEquivalentTo(customer);。相反
WhiteKnight

2
这是最好的回答这个原因
Todd Menier

ShouldBeEquivalent是越野车:(
康斯坦丁·

3
只是遇到了同样的问题,并使用了以下似乎正常的方法:actual.ShouldBeEquivalentTo(expected, x => x.ExcludingMissingMembers())
stt106

1
这是一个伟大的库!不需要覆盖Equals,并且(如果无论如何都覆盖了equals,例如对于值对象)也不需要依赖正确的实现。就像Hamcrest用于Java一样,差异也很好地打印出来。
kap

35

我不希望仅为了测试而覆盖Equals。不要忘记,如果您确实重写了Equals,则实际上也应该重写GetHashCode,否则,例如,如果在字典中使用对象,则可能会得到意外的结果。

我喜欢上面的反射方法,因为它可以满足将来增加属性的需求。

但是,对于一种快速简单的解决方案,通常最简单的方法是创建一个用于测试对象是否相等的辅助方法,或者在对测试保密的类上实现IEqualityComparer。使用IEqualityComparer解决方案时,您无需为GetHashCode的实现而烦恼。例如:

// Sample class.  This would be in your main assembly.
class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

// Unit tests
[TestFixture]
public class PersonTests
{
    private class PersonComparer : IEqualityComparer<Person>
    {
        public bool Equals(Person x, Person y)
        {
            if (x == null && y == null)
            {
                return true;
            }

            if (x == null || y == null)
            {
                return false;
            }

            return (x.Name == y.Name) && (x.Age == y.Age);
        }

        public int GetHashCode(Person obj)
        {
            throw new NotImplementedException();
        }
    }

    [Test]
    public void Test_PersonComparer()
    {
        Person p1 = new Person { Name = "Tom", Age = 20 }; // Control data

        Person p2 = new Person { Name = "Tom", Age = 20 }; // Same as control
        Person p3 = new Person { Name = "Tom", Age = 30 }; // Different age
        Person p4 = new Person { Name = "Bob", Age = 20 }; // Different name.

        Assert.IsTrue(new PersonComparer().Equals(p1, p2), "People have same values");
        Assert.IsFalse(new PersonComparer().Equals(p1, p3), "People have different ages.");
        Assert.IsFalse(new PersonComparer().Equals(p1, p4), "People have different names.");
    }
}

等于不处理空值。我将在equals方法的return语句之前添加以下内容。if(x == null && y == null){返回true; }如果(x == null || y == null){返回false;我编辑了添加空支持的问题。
鲍比·坎农

抛出新的NotImplementedException()对我不起作用;在GetHashCode中。为什么无论哪种方式我都需要在IEqualityComparer中使用该函数?
love2code

15

我尝试了这里提到的几种方法。大多数涉及序列化对象并进行字符串比较。虽然超级简单,而且通常非常有效,但是我发现当您遇到故障时,它会变得很短,并且会报告类似以下内容:

Expected string length 2326 but was 2342. Strings differ at index 1729.

至少可以说弄清楚差异在哪里。

通过FluentAssertions的对象图比较(即a.ShouldBeEquivalentTo(b)),您可以得到以下反馈:

Expected property Name to be "Foo" but found "Bar"

好多了。立即获取FluentAssertions,稍后您会感到高兴的(如果您对此表示赞同,也请在最初建议FluentAssertions 地方对dkl 的答案进行支持)。


9

我同意ChrisYoxall的观点-仅出于测试目的而在您的主代码中实现Equals是不好的。

如果您由于某些应用程序逻辑需要而实现Equals,那很好,但是请不要使用纯测试代码,以免杂乱无章(测试时检查其含义也可能与您的应用程序有所不同)。

简而言之,请将纯测试代码放在类之外。

对于大多数类,使用反射对属性进行简单的浅层比较就足够了,尽管如果对象具有复杂的属性,则可能需要递归。如果遵循以下参考,请当心循环参考或类似参考。

狡猾


循环引用很好。如果您在比较树中保留了一个对象字典,则很容易克服。
Lucas B

6

NUnit 2.4.2中添加的属性约束使解决方案比OP的原始解决方案更具可读性,并且产生的故障消息要好得多。它不是通用的,但是如果不需要太多的类,这是一个非常合适的解决方案。

Assert.That(ActualObject, Has.Property("Prop1").EqualTo(ExpectedObject.Prop1)
                          & Has.Property("Prop2").EqualTo(ExpectedObject.Prop2)
                          & Has.Property("Prop3").EqualTo(ExpectedObject.Prop3)
                          // ...

Equals虽然不像实现那样具有通用性,但是与失败相比,它确实提供了更好的故障信息

Assert.AreEqual(ExpectedObject, ActualObject);

4

Max Wikstrom的JSON解决方案(上文)对我来说最有意义,它简短,简洁,最重要的是它可以工作。就我个人而言,尽管我更喜欢将JSON转换作为一种单独的方法实现,并将断言像这样放回到单元测试中……

帮助方法:

public string GetObjectAsJson(object obj)
    {
        System.Web.Script.Serialization.JavaScriptSerializer oSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
        return oSerializer.Serialize(obj);
    }

单元测试 :

public void GetDimensionsFromImageTest()
        {
            Image Image = new Bitmap(10, 10);
            ImageHelpers_Accessor.ImageDimensions expected = new ImageHelpers_Accessor.ImageDimensions(10,10);

            ImageHelpers_Accessor.ImageDimensions actual;
            actual = ImageHelpers_Accessor.GetDimensionsFromImage(Image);

            /*USING IT HERE >>>*/
            Assert.AreEqual(GetObjectAsJson(expected), GetObjectAsJson(actual));
        }

仅供参考-您可能需要在解决方案中添加对System.Web.Extensions的引用。


4

这是一个很老的线程,但我在想,如果有,为什么没有答案提出的理由NUnit.Framework.Is.EqualToNUnit.Framework.Is.NotEqualTo

如:

Assert.That(LeftObject, Is.EqualTo(RightObject)); 

Assert.That(LeftObject, Is.Not.EqualTo(RightObject)); 

4
因为它没有打印出细节,所以有什么不同
Shrage Smilowi​​tz

1

另一种选择是通过实现NUnit抽象Constraint类来编写自定义约束。通过一个帮助程序类来提供一点语法语法,所得到的测试代码是简洁而易读的,例如

Assert.That( LeftObject, PortfolioState.Matches( RightObject ) ); 

举一个极端的例子,考虑具有“只读”成员IEquatable的类不是,即使您想更改被测类也不能:

public class Portfolio // Somewhat daft class for pedagogic purposes...
{
    // Cannot be instanitated externally, instead has two 'factory' methods
    private Portfolio(){ }

    // Immutable properties
    public string Property1 { get; private set; }
    public string Property2 { get; private set; }  // Cannot be accessed externally
    public string Property3 { get; private set; }  // Cannot be accessed externally

    // 'Factory' method 1
    public static Portfolio GetPortfolio(string p1, string p2, string p3)
    {
        return new Portfolio() 
        { 
            Property1 = p1, 
            Property2 = p2, 
            Property3 = p3 
        };
    }

    // 'Factory' method 2
    public static Portfolio GetDefault()
    {
        return new Portfolio() 
        { 
            Property1 = "{{NONE}}", 
            Property2 = "{{NONE}}", 
            Property3 = "{{NONE}}" 
        };
    }
}

Constraint该类的合同要求覆盖(Matches并且WriteDescriptionTo在不匹配的情况下,对期望值的叙述),但也应覆盖WriteActualValueTo(对实际值的叙述):

public class PortfolioEqualityConstraint : Constraint
{
    Portfolio expected;
    string expectedMessage = "";
    string actualMessage = "";

    public PortfolioEqualityConstraint(Portfolio expected)
    {
        this.expected = expected;
    }

    public override bool Matches(object actual)
    {
        if ( actual == null && expected == null ) return true;
        if ( !(actual is Portfolio) )
        { 
            expectedMessage = "<Portfolio>";
            actualMessage = "null";
            return false;
        }
        return Matches((Portfolio)actual);
    }

    private bool Matches(Portfolio actual)
    {
        if ( expected == null && actual != null )
        {
            expectedMessage = "null";
            expectedMessage = "non-null";
            return false;
        }
        if ( ReferenceEquals(expected, actual) ) return true;

        if ( !( expected.Property1.Equals(actual.Property1)
                 && expected.Property2.Equals(actual.Property2) 
                 && expected.Property3.Equals(actual.Property3) ) )
        {
            expectedMessage = expected.ToStringForTest();
            actualMessage = actual.ToStringForTest();
            return false;
        }
        return true;
    }

    public override void WriteDescriptionTo(MessageWriter writer)
    {
        writer.WriteExpectedValue(expectedMessage);
    }
    public override void WriteActualValueTo(MessageWriter writer)
    {
        writer.WriteExpectedValue(actualMessage);
    }
}

加上辅助类:

public static class PortfolioState
{
    public static PortfolioEqualityConstraint Matches(Portfolio expected)
    {
        return new PortfolioEqualityConstraint(expected);
    }

    public static string ToStringForTest(this Portfolio source)
    {
        return String.Format("Property1 = {0}, Property2 = {1}, Property3 = {2}.", 
            source.Property1, source.Property2, source.Property3 );
    }
}

用法示例:

[TestFixture]
class PortfolioTests
{
    [Test]
    public void TestPortfolioEquality()
    {
        Portfolio LeftObject 
            = Portfolio.GetDefault();
        Portfolio RightObject 
            = Portfolio.GetPortfolio("{{GNOME}}", "{{NONE}}", "{{NONE}}");

        Assert.That( LeftObject, PortfolioState.Matches( RightObject ) );
    }
}

1

我会以@Juanma的答案为基础。但是,我认为这不应与单元测试断言一起实现。这是一个非常有用的实用程序,在某些情况下非测试代码可以使用。

我写了一篇关于此事的文章http://timoch.com/blog/2013/06/unit-test-equality-is-not-domain-equality/

我的建议如下:

/// <summary>
/// Returns the names of the properties that are not equal on a and b.
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns>An array of names of properties with distinct 
///          values or null if a and b are null or not of the same type
/// </returns>
public static string[] GetDistinctProperties(object a, object b) {
    if (object.ReferenceEquals(a, b))
        return null;
    if (a == null)
        return null;
    if (b == null)
        return null;

    var aType = a.GetType();
    var bType = b.GetType();

    if (aType != bType)
        return null;

    var props = aType.GetProperties();

    if (props.Any(prop => prop.GetIndexParameters().Length != 0))
        throw new ArgumentException("Types with index properties not supported");

    return props
        .Where(prop => !Equals(prop.GetValue(a, null), prop.GetValue(b, null)))
        .Select(prop => prop.Name).ToArray();
} 

与NUnit一起使用

Expect(ReflectionUtils.GetDistinctProperties(tile, got), Empty);

在不匹配时产生以下消息。

Expected: <empty>
But was:  < "MagmaLevel" >
at NUnit.Framework.Assert.That(Object actual, IResolveConstraint expression, String message, Object[] args)
at Undermine.Engine.Tests.TileMaps.BasicTileMapTests.BasicOperations() in BasicTileMapTests.cs: line 29

1

https://github.com/kbilsted/StatePrinter专门用于将对象图转储为字符串表示形式,目的是编写简单的单元测试。

  • 带有Assert方法,该方法将正确转义的字符串轻松复制粘贴到测试中以进行更正。
  • 它允许单元测试自动重写
  • 它与所有单元测试框架集成
  • 与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);

1

只需从Nuget安装ExpectedObjects,您就可以通过匿名类型轻松比较两个对象的属性值,集合的每个对象值,两个组成的对象值和部分比较属性值。

我在github上有一些例子:https : //github.com/hatelove/CompareObjectEquals

以下是一些包含比较对象方案的示例:

    [TestMethod]
    public void Test_Person_Equals_with_ExpectedObjects()
    {
        //use extension method ToExpectedObject() from using ExpectedObjects namespace to project Person to ExpectedObject
        var expected = new Person
        {
            Id = 1,
            Name = "A",
            Age = 10,
        }.ToExpectedObject();

        var actual = new Person
        {
            Id = 1,
            Name = "A",
            Age = 10,
        };

        //use ShouldEqual to compare expected and actual instance, if they are not equal, it will throw a System.Exception and its message includes what properties were not match our expectation.
        expected.ShouldEqual(actual);
    }

    [TestMethod]
    public void Test_PersonCollection_Equals_with_ExpectedObjects()
    {
        //collection just invoke extension method: ToExpectedObject() to project Collection<Person> to ExpectedObject too
        var expected = new List<Person>
        {
            new Person { Id=1, Name="A",Age=10},
            new Person { Id=2, Name="B",Age=20},
            new Person { Id=3, Name="C",Age=30},
        }.ToExpectedObject();

        var actual = new List<Person>
        {
            new Person { Id=1, Name="A",Age=10},
            new Person { Id=2, Name="B",Age=20},
            new Person { Id=3, Name="C",Age=30},
        };

        expected.ShouldEqual(actual);
    }

    [TestMethod]
    public void Test_ComposedPerson_Equals_with_ExpectedObjects()
    {
        //ExpectedObject will compare each value of property recursively, so composed type also simply compare equals.
        var expected = new Person
        {
            Id = 1,
            Name = "A",
            Age = 10,
            Order = new Order { Id = 91, Price = 910 },
        }.ToExpectedObject();

        var actual = new Person
        {
            Id = 1,
            Name = "A",
            Age = 10,
            Order = new Order { Id = 91, Price = 910 },
        };

        expected.ShouldEqual(actual);
    }

    [TestMethod]
    public void Test_PartialCompare_Person_Equals_with_ExpectedObjects()
    {
        //when partial comparing, you need to use anonymous type too. Because only anonymous type can dynamic define only a few properties should be assign.
        var expected = new
        {
            Id = 1,
            Age = 10,
            Order = new { Id = 91 }, // composed type should be used anonymous type too, only compare properties. If you trace ExpectedObjects's source code, you will find it invoke config.IgnoreType() first.
        }.ToExpectedObject();

        var actual = new Person
        {
            Id = 1,
            Name = "B",
            Age = 10,
            Order = new Order { Id = 91, Price = 910 },
        };

        // partial comparing use ShouldMatch(), rather than ShouldEqual()
        expected.ShouldMatch(actual);
    }

参考:

  1. ExpectedObjects github
  2. 预期对象的介绍


1

我以编写一个简单的表达式工厂结束了:

public static class AllFieldsEqualityComprision<T>
{
    public static Comparison<T> Instance { get; } = GetInstance();

    private static Comparison<T> GetInstance()
    {
        var type = typeof(T);
        ParameterExpression[] parameters =
        {
            Expression.Parameter(type, "x"),
            Expression.Parameter(type, "y")
        };
        var result = type.GetProperties().Aggregate<PropertyInfo, Expression>(
            Expression.Constant(true),
            (acc, prop) =>
                Expression.And(acc,
                    Expression.Equal(
                        Expression.Property(parameters[0], prop.Name),
                        Expression.Property(parameters[1], prop.Name))));
        var areEqualExpression = Expression.Condition(result, Expression.Constant(0), Expression.Constant(1));
        return Expression.Lambda<Comparison<T>>(areEqualExpression, parameters).Compile();
    }
}

并使用它:

Assert.That(
    expectedCollection, 
    Is.EqualTo(actualCollection)
      .Using(AllFieldsEqualityComprision<BusinessCategoryResponse>.Instance));

这非常有用,因为我必须比较此类对象的集合。你可以在其他地方使用这个比较:)

这是带有示例的要点:https : //gist.github.com/Pzixel/b63fea074864892f9aba8ffde312094f


0

反序列化两个类,并进行字符串比较。

编辑: 完美地工作,这是我从NUnit获得的输出;

Test 'Telecom.SDP.SBO.App.Customer.Translator.UnitTests.TranslateEaiCustomerToDomain_Tests.TranslateNew_GivenEaiCustomer_ShouldTranslateToDomainCustomer_Test("ApprovedRatingInDb")' failed:
  Expected string length 2841 but was 5034. Strings differ at index 443.
  Expected: "...taClasses" />\r\n  <ContactMedia />\r\n  <Party i:nil="true" /..."
  But was:  "...taClasses" />\r\n  <ContactMedia>\r\n    <ContactMedium z:Id="..."
  ----------------------------------------------^
 TranslateEaiCustomerToDomain_Tests.cs(201,0): at Telecom.SDP.SBO.App.Customer.Translator.UnitTests.TranslateEaiCustomerToDomain_Tests.Assert_CustomersAreEqual(Customer expectedCustomer, Customer actualCustomer)
 TranslateEaiCustomerToDomain_Tests.cs(114,0): at Telecom.SDP.SBO.App.Customer.Translator.UnitTests.TranslateEaiCustomerToDomain_Tests.TranslateNew_GivenEaiCustomer_ShouldTranslateToDomainCustomer_Test(String custRatingScenario)

编辑二: 两个对象可以相同,但是属性序列化的顺序不同。因此,XML是不同的。DOH!

编辑三: 这确实起作用。我在测试中使用它。但是您必须按照被测代码添加项目的顺序将项目添加到集合属性中。


1
序列化?有趣的主意。不过,我不确定性能会如何提高
Michael Haren 2010年

不允许您比较给定精度的双精度数或小数。
Noctis

0

我知道这是一个非常老的问题,但是NUnit仍然对此没有本地支持。但是,如果您喜欢BDD风格的测试(ala Jasmine),您会对NExpect感到惊喜(https://github.com/fluffynuts/NExpect,从NuGet获得它),它在那里进行了深度相等性测试。

(免责声明:我是NExpect的作者)


-1

字符串化并比较两个字符串

Assert.AreEqual(JSON.stringify(LeftObject),JSON.stringify(RightObject))


-1
//Below works precisely well, Use it.
private void CompareJson()
{
object expected = new object();
object actual = new object();
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var expectedResponse = serializer.Serialize(expected);
var actualResponse = serializer.Serialize(actual);
Assert.AreEqual(expectedResponse, actualResponse);
}

感谢您提供此代码段,它可能会提供一些有限的短期帮助。通过说明为什么这是解决问题的好方法,适当的解释将大大提高其长期价值,对于其他存在类似问题的读者来说,这样做将更为有用。请编辑您的答案以添加一些解释,包括您所做的假设。
Toby Speight

这对Max的答案有什么帮助?
Toby Speight
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.