गहरे क्लोनिंग के लिए यूनिट परीक्षण

मान लीजिए कि मेरे पास एक जटिल .NET क्लास है, जिसमें बहुत सारे सरणी और अन्य क्लास ऑब्जेक्ट सदस्य हैं। मुझे इस ऑब्जेक्ट का एक गहरा क्लोन उत्पन्न करने में सक्षम होना चाहिए - इसलिए मैं क्लोन() विधि लिखता हूं, और इसे सरल बाइनरीफॉर्मेटर धारावाहिक/deserialize के साथ कार्यान्वित करता हूं - या शायद मैं किसी अन्य तकनीक का उपयोग करके गहरा क्लोन करता हूं जो अधिक त्रुटि प्रवण होता है और मैं निश्चित रूप से परीक्षण करना चाहता हूं।

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

लोग परीक्षण करने के लिए क्या दृष्टिकोण लेते हैं कि क्लोन ऑब्जेक्ट एक अच्छी प्रति है? जब आप क्लोन की आवश्यकता को खोज लेते हैं तो क्या आप लिखते हैं (या फिर से लिखना ) कक्षा के लिए आपके सभी यूनिट परीक्षण ताकि उन्हें या तो एक 'कुंवारी' ऑब्जेक्ट के साथ बुलाया जा सके < em> या इसके क्लोन के साथ? क्लोनिंग का हिस्सा पर्याप्त गहरा नहीं था, तो आप कैसे परीक्षण करेंगे - क्योंकि यह केवल ऐसी ही समस्या है जो बाद में घृणित खोज पागल दे सकती है?

0
ro fr bn

5 उत्तर

क्लोन सही था या नहीं, यह निर्धारित करने के लिए मैं सिर्फ एक ही परीक्षा लिखूंगा। यदि कक्षा को सील नहीं किया गया है, तो आप इसे विस्तारित करके इसके लिए दोहन बना सकते हैं, और उसके बाद अपने सभी आंतरिक बच्चों को कक्षा के भीतर उजागर कर सकते हैं। वैकल्पिक रूप से, आप प्रतिबिंब (यूएच) का उपयोग कर सकते हैं, या एमएसटीएस्ट के एक्सेसर जेनरेटर का उपयोग कर सकते हैं।

आपको अपनी ऑब्जेक्ट क्लोन करने की आवश्यकता है और उसके बाद प्रत्येक ऑब्जेक्ट और वैरिएबल से गुजरना है कि आपके ऑब्जेक्ट में यह निर्धारित है कि यह सही ढंग से कॉपी किया गया है या सही तरीके से क्लोन किया गया है या नहीं।

0
जोड़ा

मैं आमतौर पर दो वस्तुओं की गहराई से तुलना करने के लिए बराबर() लागू करता हूं। आपको अपने उत्पादन कोड में इसकी आवश्यकता नहीं हो सकती है लेकिन यह अभी भी बाद में काम में आ सकती है और परीक्षण कोड बहुत साफ है।

0
जोड़ा

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

अपने विशिष्ट प्रश्नों के उत्तर देने के लिए:

क्या आप लिखते हैं (या क्लोन की आवश्यकता को खोजने के बाद फिर से लिखना) कक्षा के लिए आपके सभी यूनिट परीक्षण ताकि उन्हें या तो 'कुंवारी' ऑब्जेक्ट या उसके क्लोन के साथ बुलाया जा सके?

आपके पास उन सभी विधियों के लिए परीक्षण होना चाहिए जो मूल और क्लोन ऑब्जेक्ट्स दोनों पर किए जा सकते हैं। ध्यान दें कि प्रत्येक परीक्षण के लिए तर्क को मैन्युअल रूप से अपडेट किए बिना इसका समर्थन करने के लिए एक सरल परीक्षण डिज़ाइन स्थापित करना बहुत आसान होना चाहिए।

क्लोनिंग का हिस्सा पर्याप्त गहरा नहीं था, तो आप कैसे परीक्षण करेंगे - क्योंकि यह केवल ऐसी ही समस्या है जो बाद में घृणास्पद-खोज वाली बग दे सकती है?

यह आपके द्वारा चुने गए क्लोनिंग विधि पर निर्भर करता है। यदि आपको क्लोनेबल प्रकारों को मैन्युअल रूप से अपडेट करना है तो आपको परीक्षण करना चाहिए कि प्रत्येक प्रकार आपके द्वारा अपेक्षित सदस्यों (और केवल) क्लोनिंग कर रहा है। हालांकि, यदि आप क्लोनिंग फ्रेमवर्क का परीक्षण कर रहे हैं तो मैं समर्थन के लिए आवश्यक प्रत्येक परिदृश्य का परीक्षण करने के लिए कुछ परीक्षण क्लोनेबल प्रकार बनाएगा।

0
जोड़ा

यहां एक नमूना है कि मैंने इसे थोड़ी देर पहले कैसे कार्यान्वित किया, हालांकि इसे परिदृश्य के अनुरूप बनाया जाना चाहिए। इस मामले में हमारे पास एक बुरा ऑब्जेक्ट श्रृंखला थी जो आसानी से बदल सकती थी और क्लोन का उपयोग बहुत ही महत्वपूर्ण प्रोटोटाइप कार्यान्वयन के रूप में किया जाता था और इसलिए मुझे इस परीक्षण को पैच (हैक) करना था।

public static class TestDeepClone
    {
        private static readonly List objectIDs = new List();
        private static readonly ObjectIDGenerator objectIdGenerator = new ObjectIDGenerator();

        public static bool DefaultCloneExclusionsCheck(Object obj)
        {
            return
                obj is ValueType ||
                obj is string ||
                obj is Delegate ||
                obj is IEnumerable;
        }

        /// 
/// Executes various assertions to ensure the validity of a deep copy for any object including its compositions ///
 
        /// 
The original object
        /// 
The cloned object
        /// 
A predicate for any exclusions to be done, i.e not to expect IPolicy items to be cloned
        public static void AssertDeepClone(this Object original, Object copy, Predicate checkExclude)
        {
            bool isKnown;
            if (original == null) return;
            if (copy == null) Assert.Fail("Copy is null while original is not", original, copy);

            var id = objectIdGenerator.GetId(original, out isKnown); //Avoid checking the same object more than once
            if (!objectIDs.Contains(id))
            {
                objectIDs.Add(id);
            }
            else
            {
                return;
            }

            if (!checkExclude(original))
            {
                Assert.That(ReferenceEquals(original, copy) == false);
            }

            Type type = original.GetType();
            PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
            FieldInfo[] fieldInfos = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);

            foreach (PropertyInfo memberInfo in propertyInfos)
            {
                var getmethod = memberInfo.GetGetMethod();
                if (getmethod == null) continue;
                var originalValue = getmethod.Invoke(original, new object[] { });
                var copyValue = getmethod.Invoke(copy, new object[] { });
                if (originalValue == null) continue;
                if (!checkExclude(originalValue))
                {
                    Assert.That(ReferenceEquals(originalValue, copyValue) == false);
                }

                if (originalValue is IEnumerable && !(originalValue is string))
                {
                    var originalValueEnumerable = originalValue as IEnumerable;
                    var copyValueEnumerable = copyValue as IEnumerable;
                    if (copyValueEnumerable == null) Assert.Fail("Copy is null while original is not", new[] { original, copy });
                    int count = 0;
                    List items = copyValueEnumerable.Cast().ToList(); foreach (object o in originalValueEnumerable) { AssertDeepClone(o, items[count], checkExclude); count++; } } else { //Recurse over reference types to check deep clone success if (!checkExclude(originalValue)) { AssertDeepClone(originalValue, copyValue, checkExclude); } if (originalValue is ValueType && !(originalValue is Guid)) { //check value of non reference type Assert.That(originalValue.Equals(copyValue)); } } } foreach (FieldInfo fieldInfo in fieldInfos) { var originalValue = fieldInfo.GetValue(original); var copyValue = fieldInfo.GetValue(copy); if (originalValue == null) continue; if (!checkExclude(originalValue)) { Assert.That(ReferenceEquals(originalValue, copyValue) == false); } if (originalValue is IEnumerable && !(originalValue is string)) { var originalValueEnumerable = originalValue as IEnumerable; var copyValueEnumerable = copyValue as IEnumerable; if (copyValueEnumerable == null) Assert.Fail("Copy is null while original is not", new[] { original, copy }); int count = 0; List items = copyValueEnumerable.Cast().ToList(); foreach (object o in originalValueEnumerable) { AssertDeepClone(o, items[count], checkExclude); count++; } } else { //Recurse over reference types to check deep clone success if (!checkExclude(originalValue)) { AssertDeepClone(originalValue, copyValue, checkExclude); } if (originalValue is ValueType && !(originalValue is Guid)) { //check value of non reference type Assert.That(originalValue.Equals(copyValue)); } } } } } 
0
जोड़ा

मैं यूनिट परीक्षण लिखना पसंद करता हूं जो मूल और क्लोन ऑब्जेक्ट पर बिल्टिन सीरियलाइज़र का उपयोग करता है और फिर समानता के लिए धारावाहिक प्रस्तुतियों की जांच करता है (बाइनरी फॉर्मेटर के लिए, मैं केवल बाइट एरे की तुलना कर सकता हूं)। यह उन मामलों में बहुत अच्छा काम करता है जहां ऑब्जेक्ट अभी भी क्रमबद्ध है, और मैं केवल perf कारणों के लिए एक कस्टम गहरे क्लोन में बदल रहा हूं।

इसके अलावा, मैं इस तरह के कुछ का उपयोग कर अपने क्लोन कार्यान्वयन के लिए एक डीबग मोड चेक जोड़ना चाहता हूं

[Conditional("DEBUG")]
public static void DebugAssertValueEquality(T current, T other, bool expected, 
                                               params string[] ignoredFields) {
    if (null == current) 
    { throw new ArgumentNullException("current"); }
    if (null == ignoredFields)
    { ignoredFields = new string[] { }; }

    FieldInfo lastField = null;
    bool test;
    if (object.ReferenceEquals(other, null))
    { Debug.Assert(false == expected, "The other object was null"); return; }
    test = true;
    foreach (FieldInfo fi in current.GetType().GetFields(BindingFlags.Instance)) {
        if (test = false) { break; }
        if (0 <= Array.IndexOf(ignoredFields, fi.Name))
        { continue; }
        lastField = fi;
        object leftValue = fi.GetValue(current);
        object rightValue = fi.GetValue(other);
        if (object.ReferenceEquals(null, leftValue)) {
            if (!object.ReferenceEquals(null, rightValue))
            { test = false; }
        }
        else if (object.ReferenceEquals(null, rightValue))
        { test = false; }
        else {
            if (!leftValue.Equals(rightValue))
            { test = false; }
        }
    }
    Debug.Assert(test == expected, string.Format("field: {0}", lastField));
}

यह विधि किसी भी घोंसले वाले सदस्यों पर बराबर के सटीक कार्यान्वयन पर निर्भर करती है, लेकिन मेरे मामले में जो क्लोनबल है वह भी समेकनीय है

0
जोड़ा
QAIndia
QAIndia
160 प्रतिभागियों की

QA India ! Unite Here we share job postings , prepare for interviews and share tips/techniques in QA. Please follow following guideline while sharing any job ... QA job # location : # title Company : Title : Requirement: Responsibility: Apply: