Porównaj równość dwóch obiektów w NUnit

Staram się twierdzić, że jeden obiekt jest "równy" innemu obiektowi.

Obiekty są tylko instancjami klasy z kilkoma właściwościami publicznymi. Czy istnieje łatwy sposób na stwierdzenie równości NUnit na podstawie właściwości?

To jest moje obecne rozwiązanie, ale myślę, że może być coś lepszego:

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

To, do czego zmierzam, byłoby w tym samym duchu, co zbiór, w którym NUnit weryfikuje, że zawartość dwóch zbiorów jest identyczne.

Author: Michael Haren, 2008-11-25

19 answers

Override .Równe dla Twojego obiektu i w teście jednostkowym możesz po prostu to zrobić:

Assert.AreEqual(LeftObject, RightObject);

Oczywiście, może to oznaczać, że po prostu przenieść wszystkie indywidualne porównania do .Metoda Equals, ale pozwoliłaby na ponowne wykorzystanie tej implementacji do wielu testów i prawdopodobnie ma sens mieć if obiekty i tak powinny być w stanie porównać się z rodzeństwem.

 46
Author: Lasse Vågsæther Karlsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-25 17:33:35

Jeśli z jakiegokolwiek powodu nie możesz nadpisać Equals, możesz zbudować metodę pomocniczą, która będzie powtarzana przez publiczne właściwości przez odbicie i będzie sprawdzać każdą właściwość. Coś takiego:

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]);
    }
}
 111
Author: Juanma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-08 14:57:20

Nie nadpisuj równości tylko dla celów testowych. Jest to uciążliwe i wpływa na logikę domeny. Zamiast tego

Użyj JSON, aby porównać dane obiektu

Brak dodatkowej logiki na obiektach. Brak dodatkowych zadań do testowania.

Po prostu użyj tej prostej metody:

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);
}
Wygląda na to, że świetnie się sprawdza. Informacje o wynikach testu runner pokażą porównanie ciągu JSON (Wykres obiektu) zawarte, więc widać bezpośrednio, co jest nie tak.

Uwaga! Jeśli masz większe złożone obiekty i po prostu chcesz porównać ich części możesz (użyć LINQ dla danych sekwencji) tworzyć anonimowe obiekty do użycia z powyższą metodą.

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 });
}
 90
Author: Max Wikström,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-02 22:19:58

Wypróbuj bibliotekę FluentAssertions:

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

Http://www.fluentassertions.com/

Może być również zainstalowany za pomocą NuGet.

 78
Author: dkl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-23 12:15:11

Wolę nie nadpisywać równości tylko po to, aby włączyć testowanie. Nie zapominaj, że jeśli nadpisujesz równe, naprawdę powinieneś nadpisać GetHashCode, lub możesz uzyskać nieoczekiwane wyniki, jeśli używasz obiektów w słowniku na przykład.

Podoba mi się powyższe podejście do refleksji, ponieważ dotyczy dodawania właściwości w przyszłości.

Dla szybkiego i prostego rozwiązania, jednak często najłatwiej jest stworzyć metodę pomocniczą, która sprawdza, czy obiekty są równe, lub zaimplementuj Ieequalitycomparer na klasie, którą zachowujesz prywatnie do testów. Korzystając z rozwiązania Ieequalitycomparer nie musisz się martwić o implementację GetHashCode. Na przykład:

// 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.");
    }
}
 34
Author: Chris Yoxall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-30 20:51:48

Próbowałem kilku podejść wymienionych tutaj. Większość z nich polega na serializowaniu obiektów i porównywaniu ciągów znaków. Chociaż bardzo łatwe i ogólnie bardzo skuteczne, odkryłem, że pojawia się trochę krótko, gdy masz awarię i coś takiego jest zgłaszane: {]}

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

Zastanawianie się, gdzie są różnice, jest co najmniej bolesne.

Z FluentAssertions ' porównywanie grafów obiektowych (tj. a.ShouldBeEquivalentTo(b)), otrzymujesz to z powrotem:

Expected property Name to be "Foo" but found "Bar"
To o wiele milsze. uzyskaj FluentAssertions Teraz, będziesz zadowolony później (a jeśli podniesiesz to, proszę również podświetl odpowiedź dkl gdzie FluentAssertions została po raz pierwszy zasugerowana).
 12
Author: Todd Menier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:26

Zgadzam się z ChrisYoxall -- implementowanie równości w głównym kodzie wyłącznie do celów testowych nie jest dobre.

Jeśli implementujesz Equals, ponieważ wymaga tego jakaś logika aplikacji, to jest w porządku, ale zachowaj czysty testing-tylko kod z bałaganu rzeczy(również semantyka sprawdzania tego samego dla testowania może być inna niż to, czego wymaga Twoja aplikacja).

W skrócie, zachowaj testowanie tylko kodu z klasy.

Proste porównanie właściwości za pomocą odbicie powinno wystarczyć dla większości klas, chociaż może być konieczne rekurencyjne, jeśli obiekty mają złożone właściwości. Jeśli następujące odniesienia, uważaj na odniesienia okrągłe lub podobne.

Sly

 9
Author: Sly Gryphon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-01 06:23:30

Ograniczenia właściwości , dodane w NUnit 2.4.2, pozwalają na rozwiązanie, które jest bardziej czytelne niż oryginalny OP i generuje znacznie lepsze komunikaty o błędach. Nie jest to w żaden sposób ogólne, ale jeśli nie musisz tego robić dla zbyt wielu klas, jest to bardzo odpowiednie rozwiązanie.

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

Nie tak ogólnego przeznaczenia jak implementacja Equals, ale daje znacznie lepszy komunikat o błędzie niż

Assert.AreEqual(ExpectedObject, ActualObject);
 4
Author: Paul Hicks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-15 07:10:59

Rozwiązanie JSON Maxa Wikstroma (powyżej) ma dla mnie największy sens, jest krótkie, czyste i co najważniejsze działa. Osobiście jednak wolałbym zaimplementować konwersję JSON jako osobną metodę i umieścić assert z powrotem w teście jednostkowym w taki sposób...

METODA POMOCNICZA:

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

TEST JEDNOSTKOWY:

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

FYI-być może trzeba będzie dodać odniesienie do systemu.Www.Rozszerzenia w Twoim rozwiązaniu.

 3
Author: samaspin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-29 16:40:09

Inną opcją jest napisanie własnego ograniczenia poprzez implementację klasy NUnit abstract Constraint. Z klasą pomocniczą, która dostarcza trochę cukru składniowego, uzyskany kod testowy jest przyjemnie zwięzły i czytelny, np.

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

Dla ekstremalnego przykładu, rozważ klasę, która ma członków "tylko do odczytu", nie jest IEquatable i nie możesz zmienić klasy testowanej, nawet jeśli chcesz:

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}}" 
        };
    }
}

Kontrakt dla klasy Constraint wymaga, aby zastąpić Matches i WriteDescriptionTo (w w przypadku niedopasowania, narracja dla wartości oczekiwanej), ale także nadrzędność WriteActualValueTo (narracja dla wartości rzeczywistej) ma sens:

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

Plus Klasa pomocnicza:

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

Przykładowe użycie:

[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
Author: onedaywhen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-15 14:17:23

Bazowałbym na odpowiedzi @Juanma. Uważam jednak, że nie powinno to być realizowane za pomocą twierdzeń testów jednostkowych. Jest to narzędzie, które bardzo dobrze może być używane w pewnych okolicznościach przez kod non-test.

Napisałem artykuł na ten temat http://timoch.com/blog/2013/06/unit-test-equality-is-not-domain-equality/

Moja propozycja jest następująca:

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

Używanie tego z NUnit

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

Daje następujący komunikat o niedopasowaniu.

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
Author: TiMoch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-11 09:33:42

Https://github.com/kbilsted/StatePrinter został napisany specjalnie w celu zrzutu Wykresów obiektowych do reprezentacji łańcuchów w celu napisania łatwych testów jednostkowych.

  • chodzi o metody, które wypisują poprawnie napis easy copy-paste do testu, aby go skorygować.
  • pozwala na automatyczne ponowne zapisanie unittest
  • integruje się ze wszystkimi frameworkami testów jednostkowych
  • W przeciwieństwie do serializacji JSON, odniesienia okrągłe są obsługiwane
  • możesz łatwo filtrować, więc wyrzucane są tylko części typów

Podane

class A
{
  public DateTime X;
  public DateTime Y { get; set; }
  public string Name;
}

Można w bezpieczny sposób pisać i za pomocą automatycznego uzupełniania programu visual studio zawierać lub wykluczać pola.

  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
Author: Carlo V. Dango,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-07 19:02:39

Po prostu zainstaluj ExpectedObjects z Nuget, możesz łatwo porównać wartości właściwości dwóch obiektów, wartości każdego obiektu kolekcji, dwie złożone wartości obiektu i częściowe porównanie wartości właściwości anonimowego typu.

Mam kilka przykładów na GitHubie: https://github.com/hatelove/CompareObjectEquals

Oto kilka przykładów, które zawierają scenariusze porównywania obiektów:

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

Odniesienie:

  1. ExpectedObjects github
  2. wprowadzenie ExpectedObjects
 1
Author: In91,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-24 04:37:21

Spójrz na poniższy link. Jest to rozwiązanie z code project i użyłem go też. Działa dobrze do porównywania obiektów.

Http://www.codeproject.com/Articles/22709/Testing-Equality-of-Two-Objects?msg=5189539#xx5189539xx

 1
Author: kanika,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-21 05:56:07

To dość stary wątek, ale zastanawiałem się, czy nie ma powodu, dla którego nie zaproponowano odpowiedzi NUnit.Framework.Is.EqualTo i NUnit.Framework.Is.NotEqualTo?

Takie jak:

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

I

Assert.That(LeftObject, Is.Not.EqualTo(RightObject)); 
 1
Author: user2315856,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-12 22:15:46

Deserializuje obie klasy i porównuje łańcuch znaków.

EDIT: Działa idealnie, to wyjście dostaję z 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)

EDIT TWO: Oba obiekty mogą być identyczne, ale kolejność serializacji właściwości nie jest taka sama. Dlatego XML jest inny. DOH!

EDIT THREE: To działa. Używam go w moich testach. Ale musisz dodać elementy do właściwości kolekcji w kolejności, w jakiej kod w sekcji test dodaje je.

 0
Author: Casey Burns,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-30 17:38:36

Stringify and compare two strings

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

 0
Author: jmtt89,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-09 04:11:12

Skończyłem z napisaniem prostej fabryki wyrażeń:

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

I po prostu użyj:

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

Jest to bardzo przydatne, ponieważ muszę porównać kolekcję takich obiektów. I możesz użyć tej porównywarki gdzie indziej:)

Oto gist z przykładem: https://gist.github.com/Pzixel/b63fea074864892f9aba8ffde312094f

 0
Author: Alex Zhukovskiy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-24 13:09:08

Wiem, że to naprawdę stare pytanie, ale NUnit nadal nie ma natywnego wsparcia dla tego. Jeśli jednak lubisz testy w stylu BDD (ala Jasmine), będziesz mile zaskoczony NExpect ( https://github.com/fluffynuts/NExpect , get it from NuGet), który ma głębokie testy równości.

(zastrzeżenie: jestem autorem NExpect)

 0
Author: daf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-20 13:31:42