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)

मैं जिस चीज़ के लिए जा रहा हूं, वह उसी भावना के साथ होगी जैसे कि कलेक्वलेंटकॉन्स्ट्रैटिन जिसमें एनयूनाइट यह पुष्टि करता है कि दो संग्रह की सामग्री समान हैं।

जवाबों:


51

ओवरराइड करें। अपनी वस्तु के लिए और इकाई परीक्षण में आप केवल ऐसा कर सकते हैं:

Assert.AreEqual(LeftObject, RightObject);

बेशक, इसका मतलब हो सकता है कि आप सभी व्यक्तिगत तुलनाओं को .Equals मेथड में ले जाएं, लेकिन यह आपको कई परीक्षणों के लिए उस कार्यान्वयन को फिर से उपयोग करने की अनुमति देगा, और संभवत: यह समझ में आता है कि क्या वस्तुओं को किसी भी तरह से भाई-बहन के साथ तुलना करने में सक्षम होना चाहिए।


2
धन्यवाद, Lassevk। यह मेरे लिए काम किया! मैंने लागू किया है। यहां दिए गए दिशा-निर्देशों के अनुसार। msdn.microsoft.com/en-us/library/336aedhh(VS.80).aspx
माइकल हरेन

12
और GetHashCode (), स्पष्ट रूप से ;-p
मार्क Gravell

उस पेज की सूची में नंबर 1 GetHashCode को ओवरराइड करने के लिए है, और उन्होंने कहा कि उन्होंने उन दिशानिर्देशों का पालन किया :) लेकिन हां, उस अनदेखी करने के लिए सामान्य गलती। आमतौर पर कोई गलती नहीं है जिसे आप ज्यादातर समय नोटिस करेंगे, लेकिन जब आप करते हैं, तो यह उन समयों में से एक है जब आप कहते हैं "ओह, हे, क्यों यह मेरे पतलून को सांप करता है और वह मेरी गांड क्यों काट रहा है"।
लास वी। कार्लसन

1
एक महत्वपूर्ण चेतावनी: यदि आपकी वस्तु भी लागू होती है, तो IEnumerableइसे एक संग्रह के रूप में तुलना की जाएगी, भले ही EqualsNUnit IEnumerableउच्च वरीयता देता है, लेकिन कार्यान्वयन को लागू करने की परवाह किए बिना । देखें NUnitEqualityComparer.AreEqualविवरण के लिए तरीके। आप समता बाधा के Using()तरीकों में से एक का उपयोग करके तुलनित्र को ओवरराइड कर सकते हैं । फिर भी, IEqualityComparerएडेप्टर NUnit उपयोग के कारण गैर-जेनेरिक को लागू करने के लिए पर्याप्त नहीं है ।
कालेब पेडरसन

13
अधिक कैविएट: GetHashCode()यदि आप कभी भी उस वस्तु को एक कुंजी के रूप में उपयोग करते हैं, तो उत्परिवर्तनीय प्रकारों पर लागू करना गलत व्यवहार करेगा। IMHO, ओवरराइडिंग Equals(), GetHashCode()और ऑब्जेक्ट को परीक्षण के लिए अपरिवर्तनीय बनाने का कोई मतलब नहीं है।
बावजा

118

यदि आप किसी भी कारण से बराबर नहीं कर सकते हैं, तो आप एक सहायक विधि का निर्माण कर सकते हैं जो सार्वजनिक संपत्तियों के माध्यम से प्रतिबिंब और प्रत्येक संपत्ति को मुखर करती है। कुछ इस तरह:

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

@ वेस्ली: यह सच नहीं है। Type.GetProperties विधि: वर्तमान प्रकार के सभी सार्वजनिक गुणों को लौटाता है। Msdn.microsoft.com/en-us/library/aky14axb.aspx
Sergii Volchkov

4
धन्यवाद। हालाँकि, मुझे वास्तविक और अपेक्षित पारमों के क्रम को बदलना था क्योंकि अभिसरण वास्तविक होने से पहले अपेक्षित है।
वलमास

यह एक बेहतर तरीका है IMHO, इक्वल और हैशकोड ओवरराइड्स को हर क्षेत्र की तुलना करने पर आधारित नहीं होना चाहिए और साथ ही हर वस्तु पर ऐसा करने के लिए बहुत थकाऊ है। बहुत बढ़िया!
स्कॉट व्हाइट

3
यह बहुत अच्छा काम करता है यदि आपके प्रकार में केवल मूल प्रकार ही गुण हैं। हालाँकि यदि आपके प्रकार में कस्टम प्रकार के गुण हैं (जो कि समान को लागू नहीं करते हैं) तो यह विफल हो जाएगा।
बॉबी तोप

ऑब्जेक्ट गुणों के लिए कुछ पुनरावर्तन जोड़ा गया, लेकिन मुझे अनुक्रमित गुणों को छोड़ना पड़ा:
सेहार्ट

113

केवल परीक्षण उद्देश्यों के लिए बराबरी से ज़्यादा मत करो। यह थकाऊ है और डोमेन लॉजिक को प्रभावित करता है। बजाय,

ऑब्जेक्ट के डेटा की तुलना करने के लिए 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 (जैसे किसी वेब सेवा का उपयोग करने के लिए टाइप किए गए ग्राहक का उपयोग करके) के साथ काम कर रहे हैं। यह उत्तर बहुत अधिक होना चाहिए।
रूपेश शेनॉय

1
Linq का उपयोग करें! @DmitryBLR (उत्तर में अंतिम पैराग्राफ देखें) :)
अधिकतम

3
यह एक महान विचार है। मैं नए Json.NET का उपयोग करेगा: var अपेक्षितजसन = Newtonsoft.Json.JsonConvert.SerializeObject (अपेक्षित);
BrokeMyLegBiking

2
यह परिपत्र संदर्भों के साथ काम नहीं करेगा। JSON दृष्टिकोण पर बेहतर अनुभव के लिए github.com/kbilsted/StatePrinter का उपयोग करें
कार्लो वी। डंगो

2
यह सच है @KokaChernov और कभी-कभी आप परीक्षण विफल करना चाहते हैं यदि ऑर्डरिंग समान नहीं है, लेकिन यदि आप असफल नहीं होना चाहते हैं यदि ऑर्डरिंग समान नहीं है, तो आप उन्हें AreEalalBitson विधि से पास करने से पहले सूचियों पर स्पष्ट प्रकार (linq का उपयोग करके) कर सकते हैं। परीक्षण से पहले अपनी वस्तुओं को "पुन: व्यवस्थित" करने का एक सरल संस्करण उत्तर में अंतिम कोड उदाहरण में है। तो मुझे लगता है कि बहुत "सार्वभौमिक" है! :)
अधिकतम

91

फ़्लुएंटेसरीज लाइब्रेरी आज़माएँ:

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

http://www.fluentassertions.com/

इसे NuGet का उपयोग करके भी स्थापित किया जा सकता है।


18
कंधे को छोटा कर दिया गया है, इसलिए dto.ShouldBeEquivalentTo (ग्राहक) होना चाहिए; इसके बजाय
व्हाइटकेन

2
यह है के लिए सबसे अच्छा जवाब है इस कारण से
टोड मेनियर

कंडेक्विंटेंट छोटी गाड़ी है :(
कॉन्स्टेंटिन

3
बस एक ही समस्या थी और निम्नलिखित का उपयोग किया गया था जो ठीक काम कर रहा है:actual.ShouldBeEquivalentTo(expected, x => x.ExcludingMissingMembers())
stt106

1
यह एक महान कामेच्छा है! समतुल्य को ओवरराइड करने की आवश्यकता नहीं है और (यदि बराबरी वैसे भी बहुत अधिक है, जैसे मूल्य वस्तुओं के लिए) सही कार्यान्वयन पर भरोसा नहीं करता है। इसके अलावा अंतर अच्छी तरह से मुद्रित किया जाता है, जैसे हैमरेस्ट जावा के लिए करता है।
kap

35

मैं परीक्षण को सक्षम करने के लिए सिर्फ बराबरी को पार नहीं करना पसंद करता हूं। यह मत भूलो कि यदि आप ओवरराइड करते हैं, तो आपको वास्तव में 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.");
    }
}

बराबरी शून्य मानों को संभालती नहीं है। मैं आपके रिटर्न स्टेटमेंट से पहले निम्नलिखित को समान विधि में शामिल करूंगा। अगर (x == null && y == null) {वापसी सच; } अगर (x == null || y == null) {झूठी; } मैंने अशक्त समर्थन जोड़ने के लिए प्रश्न संपादित किया।
बॉबी तोप

नए NotImplementedException () फेंकने के साथ मेरे लिए काम नहीं कर रहा है; GetHashCode में। मुझे IEqualityComparer में किसी भी तरह से उस फ़ंक्शन की आवश्यकता क्यों है?
love2code

15

मैंने यहां बताए गए कई तरीकों की कोशिश की है। अधिकांश में आपकी वस्तुओं को क्रमबद्ध करना और एक स्ट्रिंग तुलना करना शामिल है। सुपर आसान और आम तौर पर बहुत प्रभावी होते हुए, मैंने पाया है कि जब आप असफल होते हैं तो यह थोड़ा कम हो जाता है और इस तरह से कुछ रिपोर्ट किया जाता है:

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

यह पता लगाना कि मतभेद कहाँ हैं, कम से कम कहने के लिए दर्द है।

फ्लुएंटसॉर्शन की वस्तु ग्राफ तुलना (यानी a.ShouldBeEquivalentTo(b)) के साथ, आपको यह वापस मिल जाएगा:

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

यह बहुत अच्छा है। अब FluentAssertions प्राप्त करें , आपको बाद में खुशी होगी (और यदि आप इसे बढ़ाते हैं, तो कृपया Dkl के उत्तर को भी छोड़ दें जहाँ पहले FluentAssertions का सुझाव दिया गया था)।


9

मैं क्रिसयॉक्स के साथ सहमत हूं - परीक्षण के प्रयोजनों के लिए विशुद्ध रूप से अपने मुख्य कोड में बराबर को लागू करना अच्छा नहीं है।

यदि आप इक्वल को लागू कर रहे हैं क्योंकि कुछ एप्लिकेशन लॉजिक की आवश्यकता है, तो यह ठीक है, लेकिन शुद्ध परीक्षण-केवल कोड को अव्यवस्था के सामान से बाहर रखें (परीक्षण के लिए उसी की जाँच करने का शब्दार्थ आपके ऐप के लिए भिन्न हो सकता है)।

संक्षेप में, परीक्षण-केवल कोड को अपनी कक्षा से बाहर रखें।

परावर्तन का उपयोग करने वाले गुणों की सरल उथली तुलना अधिकांश वर्गों के लिए पर्याप्त होनी चाहिए, हालाँकि आपकी वस्तुओं के जटिल गुण होने पर आपको पुनरावृत्ति करने की आवश्यकता हो सकती है। यदि संदर्भों का अनुसरण करते हैं, तो परिपत्र संदर्भों या इसी तरह से सावधान रहें।

धूर्त


परिपत्र संदर्भ पर अच्छी पकड़। यदि आप तुलना पेड़ में पहले से ही वस्तुओं का एक शब्दकोश रखते हैं तो दूर करना आसान है।
लुकास बी

6

संपत्ति की कमी , NUnit 2.4.2 में जोड़ा गया, एक समाधान की अनुमति देता है जो ओपी के मूल से अधिक पठनीय है, और यह बहुत बेहतर विफलता संदेश उत्पन्न करता है। यह किसी भी तरह से सामान्य नहीं है, लेकिन अगर आपको इसे कई वर्गों के लिए करने की आवश्यकता नहीं है, तो यह एक बहुत ही पर्याप्त समाधान है।

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

मैक्स विकस्ट्रॉम का 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));
        }

FYI करें - आपको अपने समाधान में System.Web.Extensions में एक संदर्भ जोड़ना होगा।


4

यह एक बहुत पुराना धागा है, लेकिन मैं सोच रहा था कि क्या कोई कारण है कि कोई उत्तर प्रस्तावित नहीं है NUnit.Framework.Is.EqualToऔर NUnit.Framework.Is.NotEqualTo?

जैसे कि:

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

तथा

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

4
क्योंकि यह अलग
श्रेज स्माइलोवित्ज़

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

मैं @ जुआनमा के उत्तर पर निर्माण करूंगा। हालांकि, मेरा मानना ​​है कि इसे इकाई परीक्षण के साथ लागू नहीं किया जाना चाहिए। यह एक उपयोगिता है जिसे गैर-परीक्षण कोड द्वारा कुछ परिस्थितियों में बहुत अच्छी तरह से उपयोग किया जा सकता है।

मैंने इस मामले पर एक लेख लिखा है 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 को विशेष रूप से आसान यूनिट टेस्ट लिखने के उद्देश्य से स्ट्रिंग प्रतिनिधित्व के लिए ऑब्जेक्ट ग्राफ़ को डंप करने के लिए लिखा गया है।

  • यह witg Assert तरीके आता है जो इसे ठीक करने के लिए परीक्षण में एक अच्छी तरह से बची हुई स्ट्रिंग आसान कॉपी-पेस्ट का उत्पादन करता है।
  • यह unittest को स्वचालित रूप से फिर से लिखे जाने की अनुमति देता है
  • यह सभी इकाई परीक्षण ढांचे के साथ एकीकृत होता है
  • JSON क्रमांकन के विपरीत, परिपत्र संदर्भ समर्थित हैं
  • आप आसानी से फ़िल्टर कर सकते हैं, इसलिए केवल प्रकारों के कुछ हिस्सों को डंप किया जाता है

दिया हुआ

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

आप एक सुरक्षित तरीके से कर सकते हैं, और दृश्य स्टूडियो के ऑटो-समापन का उपयोग करके फ़ील्ड शामिल या बाहर कर सकते हैं।

  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. ExpectedObjects का परिचय

1

निम्नलिखित लिंक पर एक नज़र है। इसका कोड प्रोजेक्ट से समाधान है और मैंने इसका उपयोग भी किया है। यह वस्तुओं की तुलना करने के लिए ठीक काम करता है।

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


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)

EDIT TWO: दो ऑब्जेक्ट समान हो सकते हैं, लेकिन गुण क्रमबद्ध हैं जो क्रम समान नहीं हैं। इसलिए XML अलग है। DOH!

संपादित करें: यह काम करता है। मैं अपने परीक्षणों में इसका उपयोग कर रहा हूं। लेकिन आपको आइटम को संग्रह गुणों में जोड़ना होगा क्रम में परीक्षण के तहत कोड उन्हें जोड़ता है।


1
क्रमबद्ध करें ? दिलचस्प विचार। मुझे यकीन नहीं है कि यह प्रदर्शन के मामले में कैसा रहेगा, हालांकि
माइकल हरेन

आप किसी दिए गए सटीक के साथ डबल्स या दशमलव की तुलना करने की अनुमति नहीं देंगे।
नॉक्टिस

0

मुझे पता है कि यह वास्तव में एक पुराना सवाल है, लेकिन Nnnit के पास अभी भी इसके लिए मूल समर्थन नहीं है। हालाँकि, यदि आप 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);
}

इस कोड स्निपेट के लिए धन्यवाद, जो कुछ सीमित अल्पकालिक सहायता प्रदान कर सकता है। एक उचित व्याख्या यह दर्शाती है कि समस्या का एक अच्छा समाधान क्यों है, यह दिखा कर इसके दीर्घकालिक मूल्य में बहुत सुधार होगा , और यह भविष्य के पाठकों को अन्य, समान प्रश्नों के साथ और अधिक उपयोगी बना देगा। कृपया कुछ स्पष्टीकरण जोड़ने के लिए अपने उत्तर को संपादित करें, जिसमें आपके द्वारा की गई धारणाएँ शामिल हैं।
टोबी स्पाईट

और यह मैक्स के जवाब में क्या जोड़ता है ?
टोबी स्पाईट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.