NUnit'te iki nesne arasındaki eşitliği karşılaştırın


126

Bir nesnenin başka bir nesneye "eşit" olduğunu iddia etmeye çalışıyorum.

Nesneler, bir grup genel özelliğe sahip bir sınıfın örnekleridir. NUnit'in özelliklere dayalı olarak eşitlik iddiasında bulunmasının kolay bir yolu var mı?

Bu benim şu anki çözümüm ama daha iyi bir şey olabileceğini düşünüyorum:

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

NUnit'in iki koleksiyonun içeriğinin aynı olduğunu doğruladığı CollectionEquivalentConstraint ile aynı ruha sahip olacaktım.

Yanıtlar:


51

Nesneniz için Eşitleri geçersiz kılın ve birim testinde bunu basitçe yapabilirsiniz:

Assert.AreEqual(LeftObject, RightObject);

Elbette, bu, tüm bireysel karşılaştırmaları .Equals yöntemine taşıdığınız anlamına gelebilir, ancak bu uygulamayı birden çok test için yeniden kullanmanıza izin verir ve muhtemelen nesnelerin kendilerini kardeşleriyle karşılaştırabilmeleri gerekiyorsa mantıklıdır.


2
Teşekkürler lassevk. Bu benim için çalıştı! .Equals'i şuradaki yönergelere göre uyguladım: msdn.microsoft.com/en-us/library/336aedhh(VS.80).aspx
Michael Haren

12
Ve GetHashCode (), belli ki ;-p
Marc Gravell

O sayfadaki listedeki 1 numara GetHashCode'u geçersiz kılmaktır ve o yönergeleri izlediğini söyledi :) Ama evet, bunu görmezden gelmek için yaygın bir hata. Genellikle bir hata değil, çoğu zaman fark edeceksiniz, ancak bunu yaptığınızda, "Oh, hey, bu yılan neden pantolonumu giyiyor ve neden kıçımı ısırıyor" dediğiniz zamanlardan biri gibi.
Lasse V. Karlsen

1
Önemli bir uyarı: Nesneniz de IEnumerableuyguluyorsa, EqualsNUnit IEnumerabledaha yüksek öncelik verdiği için , geçersiz kılan uygulamalara bakılmaksızın bir koleksiyon olarak karşılaştırılacaktır . Ayrıntılar için NUnitEqualityComparer.AreEqualyöntemlere bakın. Eşitlik kısıtlamasının Using()yöntemlerinden birini kullanarak karşılaştırıcıyı geçersiz kılabilirsiniz . O zaman bile, IEqualityComparerNUnit'in kullandığı bağdaştırıcı nedeniyle jenerik olmayanın uygulanması yeterli değildir .
Kaleb Pederson

13
Daha Fazla Uyarı: GetHashCode()Bu nesneyi bir anahtar olarak kullanırsanız, değiştirilebilir türler üzerinde uygulama yanlış davranacaktır. IMHO, ağır basan Equals(), GetHashCode()ve sadece mantıklı değil test etmek için nesne değişmez yapma.
bavaza

118

Herhangi bir nedenle Eşittir'i geçersiz kılamazsanız, yansıtma yoluyla genel özellikleri yineleyen ve her özelliği iddia eden bir yardımcı yöntem oluşturabilirsiniz. Bunun gibi bir şey:

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: Bu doğru değil. Type.GetProperties Yöntemi: Geçerli Türün tüm genel özelliklerini döndürür. Bkz msdn.microsoft.com/en-us/library/aky14axb.aspx
Sergii Volchkov

4
Teşekkürler. bununla birlikte, gerçek ve beklenen parametrelerin sırasını değiştirmek zorunda kaldım çünkü dönüşüm, beklenen bir değerdir.
Valamas

bu daha iyi bir yaklaşımdır IMHO, Equal & HashCode geçersiz kılma işlemlerinin her alanı karşılaştırmaya dayanması gerekmez ve bu, her nesnede yapılması çok sıkıcıdır. Aferin!
Scott White

3
Bu, türünüzde özellik olarak yalnızca temel türler varsa harika çalışır. Ancak türünüzün özel türlere sahip özellikleri varsa (Eşittir uygulamayan) başarısız olur.
Bobby Cannon

Nesne özellikleri için bazı özyineleme eklendi, ancak indekslenmiş özellikleri atlamak zorunda kaldım:
cerhart

113

Eşittir'i yalnızca test amacıyla geçersiz kılmayın. Sıkıcıdır ve alan mantığını etkiler. Yerine,

Nesnenin verilerini karşılaştırmak için JSON kullanın

Nesnelerinizde ek mantık yok. Test için ekstra görev yok.

Sadece şu basit yöntemi kullanın:

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

Harika çalışıyor gibi görünüyor. Test çalıştırıcısı sonuç bilgisi, dahil olan JSON dizesi karşılaştırmasını (nesne grafiği) gösterecek ve böylece neyin yanlış olduğunu doğrudan görmelisiniz.

Ayrıca unutmayın! Daha büyük karmaşık nesneleriniz varsa ve yalnızca parçalarını karşılaştırmak istiyorsanız, ( sıra verileri için LINQ kullanın ) yukarıdaki yöntemle kullanmak için anonim nesneler oluşturabilirsiniz.

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
Bu, özellikle JSON ile zaten uğraşıyorsanız (örneğin, bir web hizmetine erişmek için yazılı bir istemci kullanıyorsanız) test etmenin mükemmel bir yoludur. Bu cevap çok daha yüksek olmalı.
Roopesh Shenoy

1
Linq'i kullanın! @DmitryBLR :) (yanıtında son paragrafa bakınız)
Max

3
Bu harika bir fikir. Daha yeni Json.NET'i kullanırdım: var beklenenJson = Newtonsoft.Json.JsonConvert.SerializeObject (beklenen);
BrokeMyLegBiking

2
Bu, döngüsel referanslarla çalışmaz. Kullanım github.com/kbilsted/StatePrinter yerine JSON yöntemden daha gelişmiş bir deneyim için
Carlo V. Dango

2
Bu doğru @KokaChernov ve bazen sıralama aynı değilse testte başarısız olmak istersiniz, ancak sıralama aynı değilse başarısız olmak istemiyorsanız, listeleri AreEqualByJson yöntemine geçirmeden önce açık sıralama (linq kullanarak) yapabilirsiniz. Test etmeden önce nesnelerinizi "yeniden düzenlemenin" basit bir varyantı, yanıttaki son kod örneğindedir. Yani bence bu çok "evrensel"! :)
Max

91

FluentAssertions kitaplığını deneyin:

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

http://www.fluentassertions.com/

NuGet kullanılarak da kurulabilir.


18
ShouldHave kullanımdan kaldırıldı, bu nedenle dto.ShouldBeEquivalentTo (müşteri) olmalıdır; bunun yerine
WhiteKnight

2
Bu nedenle en iyi cevap budur .
Todd Menier

ShouldBeEquivalent buggy :(
Konstantin Chernov

3
sadece aynı sorunu actual.ShouldBeEquivalentTo(expected, x => x.ExcludingMissingMembers())
yaşadım ve

1
Bu harika bir kitaptır! Eşittir'i geçersiz kılmayı gerektirmez ve aynı zamanda (eşittir yine de geçersiz kılınırsa, örneğin değer nesneleri için) doğru uygulamaya dayanmaz. Ayrıca, Hamcrest'in Java için yaptığı gibi, fark güzelce basılmıştır.
kap

35

Yalnızca testi etkinleştirmek için Eşittir'i geçersiz kılmamayı tercih ediyorum. Eşittir'i geçersiz kılarsanız, GetHashCode'u da gerçekten geçersiz kılmanız gerektiğini veya örneğin nesnelerinizi bir sözlükte kullanıyorsanız beklenmedik sonuçlar elde edebileceğinizi unutmayın.

Gelecekte mülklerin eklenmesi için sunulduğu için yukarıdaki yansıtma yaklaşımını seviyorum.

Bununla birlikte, hızlı ve basit bir çözüm için, nesnelerin eşit olup olmadığını test eden yardımcı bir yöntem oluşturmak veya testlerinize özel tuttuğunuz bir sınıfta IEqualityComparer uygulamak en kolayıdır. IEqualityComparer çözümünü kullanırken GetHashCode uygulamasıyla uğraşmanıza gerek yoktur. Örneğin:

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

Eşittir, boş değerleri işlemez. Eşittir yönteminde return ifadenizin önüne aşağıdakileri eklerim. eğer (x == null && y == null) {dönüş doğru; } eğer (x == null || y == null) {dönüş yanlış; } Boş destek eklemek için soruyu düzenledim.
Bobby Cannon

Yeni NotImplementedException () ile benim için çalışmıyor; GetHashCode'da. Neden IEqualityComparer'da bu işleve her iki şekilde de ihtiyacım var?
love2code

15

Burada bahsedilen birkaç yaklaşımı denedim. Çoğu, nesnelerinizi serileştirmeyi ve bir dizi karşılaştırması yapmayı içerir. Süper kolay ve genellikle çok etkili olsa da, bir başarısızlığın olduğunda bunun biraz kısa sürdüğünü ve bunun gibi bir şeyin rapor edildiğini gördüm:

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

Farklılıkların nerede olduğunu bulmak, en hafif tabirle bir acıdır.

FluentAssertions'ın nesne grafiği karşılaştırmaları (yani a.ShouldBeEquivalentTo(b)) ile şunu geri alırsınız:

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

Bu çok daha hoş. FluentAssertions'ı şimdi edinin , daha sonra sevineceksiniz (ve buna ek oy verirseniz , lütfen aynı zamanda dkl'ın cevabını FluentAssertions'ın ilk önerildiği yere yükseltin).


9

ChrisYoxall'a katılıyorum - Eşitleri ana kodunuzda yalnızca test amacıyla uygulamak iyi değildir.

Equals'ı bazı uygulama mantığı gerektirdiği için uyguluyorsanız, sorun değil, ancak salt test amaçlı kodu dağınıklıktan uzak tutun (ayrıca test için aynı şeyi kontrol etmenin anlamı, uygulamanızın gerektirdiğinden farklı olabilir).

Kısacası, yalnızca test amaçlı kodu sınıfınızın dışında tutun.

Nesnelerinizin karmaşık özellikleri varsa tekrarlamanız gerekse de, yansıma kullanarak özelliklerin basit yüzeysel karşılaştırması çoğu sınıf için yeterli olacaktır. Aşağıdaki referanslar varsa, döngüsel referanslara veya benzerlerine dikkat edin.

sinsi


Döngüsel referanslarda güzel yakalama. Zaten karşılaştırma ağacında nesnelerin sözlüğünü tutarsanız üstesinden gelmek kolaydır.
Lucas B

6

NUnit 2.4.2'de eklenen özellik kısıtlamaları , OP'nin orijinal çözümünden daha okunabilir bir çözüme izin verir ve çok daha iyi hata mesajları üretir. Hiçbir şekilde genel değildir, ancak çok fazla sınıf için yapmanız gerekmiyorsa, bu çok uygun bir çözümdür.

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

Uygulama kadar genel amaçlı değil Equalsama çok daha iyi bir hata mesajı veriyor

Assert.AreEqual(ExpectedObject, ActualObject);

4

Max Wikstrom'un JSON çözümü (yukarıda) benim için en mantıklı olanı, kısa, temiz ve en önemlisi işe yarıyor. Şahsen JSON dönüşümünü ayrı bir yöntem olarak uygulamayı ve iddiayı tekrar birim testinin içine yerleştirmeyi tercih etsem de ...

YARDIMCI YÖNTEM:

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

ÜNİTE TESTİ :

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

Bilginize - Çözümünüzde System.Web.Extensions için bir referans eklemeniz gerekebilir.


4

Bu oldukça eski iplik ama cevap önermiştir bir nedeni var acaba NUnit.Framework.Is.EqualTove NUnit.Framework.Is.NotEqualTo?

Gibi:

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

ve

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

4
Çünkü neyin farklı olduğunu ayrıntıları yazdırmıyor
Shrage Smilowitz

1

Diğer bir seçenek, NUnit soyut Constraintsınıfını uygulayarak özel bir kısıtlama yazmaktır . Biraz sözdizimsel şeker sağlamak için yardımcı bir sınıfla, ortaya çıkan test kodu hoş bir şekilde kısa ve okunabilir örn.

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

Uç bir örnek için, 'salt okunur' üyeleri IEquatableolan sınıfın olmadığını ve aşağıdakileri yapmak isteseniz bile test edilen sınıfı değiştiremeyeceğinizi düşünün:

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

ConstraintSınıf için sözleşme , birinin geçersiz kılmasını gerektirir Matchesve WriteDescriptionTo(bir uyumsuzluk durumunda, beklenen değer için bir anlatım) ama aynı zamanda geçersiz kılmak WriteActualValueTo(gerçek değer için anlatı) mantıklıdır:

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

Ayrıca yardımcı sınıf:

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

Örnek kullanım:

[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'nın cevabına dayanırdım. Ancak, bunun birim test iddiaları ile uygulanmaması gerektiğine inanıyorum. Bu, bazı durumlarda test dışı kod tarafından çok iyi kullanılabilen bir yardımcı programdır.

Konuyla ilgili bir makale yazdım http://timoch.com/blog/2013/06/unit-test-equality-is-not-domain-equality/

Benim önerim şu şekildedir:

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

Bunu NUnit ile kullanma

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

uyumsuzluk durumunda aşağıdaki mesajı verir.

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 , kolay birim testleri yazmak amacıyla özellikle nesne grafiklerini dize gösterimine dökmek için yazılmıştır.

  • Düzgün bir şekilde kaçmış bir dizeyi düzeltmek için teste kolayca kopyalayıp yapıştıran Witg Assert yöntemleri ile birlikte gelir.
  • Birim testinin otomatik olarak yeniden yazılmasına izin verir
  • Tüm birim test çerçeveleriyle bütünleşir
  • JSON serileştirmenin aksine döngüsel referanslar desteklenir
  • Kolayca filtreleyebilirsiniz, böylece türlerin yalnızca bazı kısımları atılır

verilmiş

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

Güvenli bir şekilde ve visual studio otomatik tamamlamayı kullanarak alanları dahil edebilir veya hariç tutabilirsiniz.

  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

Sadece Nuget'ten ExpectedObjects yükleyin, iki nesnenin özellik değerini, koleksiyonun her bir nesne değerini, iki oluşturulmuş nesnenin değerini ve anonim türe göre kısmi karşılaştırma özellik değerini kolayca karşılaştırabilirsiniz.

Github'da bazı örneklerim var: https://github.com/hatelove/CompareObjectEquals

Nesneyi karşılaştırma senaryolarını içeren bazı örnekler şunlardır:

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

Referans:

  1. ExpectedObjects github
  2. ExpectedObjects'e Giriş


1

Basit bir ifade fabrikası yazmakla bitirdim:

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

ve sadece kullanın:

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

Bu tür nesnelerin koleksiyonunu karşılaştırmak zorunda olduğum için çok kullanışlı. Ve bunu başka bir yerde karşılaştırabilirsiniz :)

İşte örnekle özet: https://gist.github.com/Pzixel/b63fea074864892f9aba8ffde312094f


0

Her iki sınıfı da seri durumdan çıkarın ve bir dize karşılaştırması yapın.

DÜZENLEME: Mükemmel çalışıyor, bu NUnit'ten aldığım çıktı;

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)

İKİNCİ DÜZENLEME: İki nesne aynı olabilir, ancak özelliklerin serileştirildiği sıra aynı değildir. Bu nedenle XML farklıdır. DOH!

ÜÇÜNCÜ DÜZENLE: Bu işe yarıyor. Testlerimde kullanıyorum. Ancak, test edilen kodun bunları ekleme sırasına göre koleksiyon özelliklerine öğe eklemelisiniz.


1
seri hale getirmek mi? İlginç fikir. Yine de performans açısından nasıl dayanacağını bilmiyorum
Michael Haren

çiftleri veya ondalık sayıları belirli bir hassasiyetle karşılaştırmanıza izin vermez.
Noctis

0

Bunun gerçekten eski bir soru olduğunu biliyorum, ancak NUnit hala bunun için yerel desteğe sahip değil. Bununla birlikte, BDD tarzı testi (ala Jasmine) seviyorsanız , orada derin eşitlik testleri yapılan NExpect'e ( https://github.com/fluffynuts/NExpect , NuGet'ten alın) hoş bir şekilde şaşıracaksınız. .

(feragatname: NExpect'in yazarıyım)


-1

İki dizeyi dizgiye çevirin ve karşılaştırın

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

Kısa vadeli sınırlı yardım sağlayabilecek bu kod parçacığı için teşekkür ederiz. Uygun bir açıklama , bunun neden soruna iyi bir çözüm olduğunu göstererek uzun vadeli değerini büyük ölçüde artıracak ve diğer benzer sorularla gelecekteki okuyucular için daha yararlı hale getirecektir. Yaptığınız varsayımlar da dahil olmak üzere bazı açıklamalar eklemek için lütfen cevabınızı düzenleyin .
Toby Speight

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.