संरचनाओं की तुलना करते समय यह मुखर एक प्रारूप अपवाद को क्यों फेंकता है?


94

मैं दो System.Drawing.Sizeसंरचनाओं की समानता का दावा करने की कोशिश कर रहा हूं , और मुझे आशा की विफलता के बजाय एक प्रारूप अपवाद मिल रहा है।

[TestMethod]
public void AssertStructs()
{
    var struct1 = new Size(0, 0);
    var struct2 = new Size(1, 1);

    //This throws a format exception, "System.FormatException: Input string was not in a correct format."
    Assert.AreEqual(struct1, struct2, "Failed. Expected {0}, actually it is {1}", struct1, struct2); 

    //This assert fails properly, "Failed. Expected {Width=0, Height=0}, actually it is {Width=1, Height=1}".
    Assert.AreEqual(struct1, struct2, "Failed. Expected " + struct1 + ", actually it is " + struct2); 
}

क्या यह इच्छित व्यवहार है? क्या मुझसे यहां कुछ गलत हो रहा है?


क्या आपने होने की कोशिश की है Assert.AreEqual(struct1, struct2, string.Format("Failed expected {0} actually is {1}, struct1.ToString (), struct2.ToString ())) `?
डिस्कजंकी

यह ठीक काम करता है; हालाँकि मैं इस बात को लेकर उत्सुक हूं कि Assert.AreEqual () संरचना प्रकारों के साथ एक स्ट्रिंग को प्रारूपित नहीं कर सकता है।
काइल

@ केइल आउट ऑफ क्यूरियोसिटी, यह यूनिट टेस्टिंग फ्रेमवर्क के सिल्वरलाइट संगत संस्करण के साथ नहीं है, है ना? मैं इसे उन DLL के साथ पुन: उत्पन्न कर सकता हूं (अभी तक पूर्ण .NET फ्रेमवर्क संस्करण की कोशिश नहीं की है) EDIT: कभी नहीं, पूर्ण के साथ परीक्षण किया और अभी भी विफल रहा। :)
क्रिस सिंक्लेयर

@ क्रिसहिन्क्लेयर नोप, यह विजुअल स्टूडियो 2010 अल्टीमेट के साथ आने वाले मैस्टेस्ट के किसी भी संस्करण का उपयोग कर रहा है। परीक्षण परियोजना स्वयं .NET फ्रेमवर्क 4
काइल

4
यकीन नहीं है कि आप एक लानत दे, लेकिन यह NUnit में ठीक काम करता है। मैंने MStest में इन जैसे और भी "मुद्दे" देखे हैं। NUnit थोड़ा अधिक परिपक्व लगता है (मेरे लिए कम से कम)। पोस्ट के लिए +1
Bas

जवाबों:


100

मुझे मिलगया। और हाँ, यह एक बग है।

समस्या यह है कि यहां पर दो स्तर string.Formatहैं।

पहले स्वरूपण के स्तर की तरह कुछ है:

string template  = string.Format("Expected: {0}; Actual: {1}; Message: {2}",
                                 expected, actual, message);

फिर हम string.Formatआपके द्वारा दिए गए मापदंडों का उपयोग करते हैं:

string finalMessage = string.Format(template, parameters);

(जाहिर है संस्कृतियों प्रदान की जा रही है, और है कुछ सफ़ाई की तरह ... लेकिन पर्याप्त नहीं।)

यह ठीक लग रहा है - जब तक अपेक्षित और वास्तविक मूल्य खुद को ब्रेसिज़ के साथ समाप्त नहीं करते हैं, एक स्ट्रिंग में परिवर्तित होने के बाद - जो वे करते हैं Size। उदाहरण के लिए, आपका पहला आकार समाप्त हो रहा है:

{Width=0, Height=0}

तो स्वरूपण का दूसरा स्तर कुछ इस प्रकार है:

string.Format("Expected: {Width=0, Height=0}; Actual: {Width=1, Height=1 }; " +
              "Message = Failed expected {0} actually is {1}", struct1, struct2);

... और यही असफलता है। आउच।

वास्तव में, हम उम्मीद और वास्तविक भागों के लिए अपने मापदंडों का उपयोग करने के लिए प्रारूपण को बेवकूफ बनाकर इसे आसानी से साबित कर सकते हैं:

var x = "{0}";
var y = "{1}";
Assert.AreEqual<object>(x, y, "What a surprise!", "foo", "bar");

परिणाम है:

Assert.AreEqual failed. Expected:<foo>. Actual:<bar>. What a surprise!

स्पष्ट रूप से टूट गया, क्योंकि हम उम्मीद नहीं कर रहे थे fooऔर न ही वास्तविक मूल्य था bar!

मूल रूप से यह एक SQL इंजेक्शन हमले की तरह है, लेकिन इसके बजाय कम डरावने संदर्भ में है string.Format

वर्कअराउंड के रूप में, आप string.Formatस्ट्रिपलिंगवर्यर के सुझाव के रूप में उपयोग कर सकते हैं । यह वास्तविक / अपेक्षित मूल्यों के साथ स्वरूपण के परिणाम पर किए जा रहे स्वरूपण के दूसरे स्तर से बचा जाता है।


विस्तृत जवाब जॉन के लिए धन्यवाद! मैंने स्ट्रिपलिंगवेयर का उपयोग करते हुए अंत में काम किया।
काइल

1
नहीं के %*nबराबर? :(
टॉम हॉन्टिन - 20

क्या किसी ने इसके लिए बग रिपोर्ट प्रस्तुत की है?
केविन

@ केविन: हाँ - हालांकि आंतरिक रूप से, इसलिए मुझे यकीन नहीं है कि प्रगति सार्वजनिक रूप से दिखाई देगी जब तक यह तय नहीं हो जाता।
जॉन स्कीट

1
@ केविन मैंने एमएस में एक डाल दिया और साथ ही एक बग की पुष्टि की। connect.microsoft.com/VisualStudio/feedback/details/779528/… यदि आप इसे सार्वजनिक रूप से ट्रैक करना चाहते हैं।
काइल

43

मुझे लगता है कि आपको एक बग मिल गया है।

यह काम करता है (एक जोरदार अपवाद फेंकता है):

var a = 1;
var b = 2;
Assert.AreEqual(a, b, "Not equal {0} {1}", a, b);

और यह काम करता है (संदेश आउटपुट):

var a = new{c=1};
var b = new{c=2};
Console.WriteLine(string.Format("Not equal {0} {1}", a, b));

लेकिन यह काम नहीं करता है (फेंकता है FormatException):

var a = new{c=1};
var b = new{c=2};
Assert.AreEqual(a, b, "Not equal {0} {1}", a, b);

मैं किसी भी कारण के बारे में सोच नहीं सकता यह अपेक्षित व्यवहार होगा। मैं एक बग रिपोर्ट प्रस्तुत करूंगा। इस बीच, यहाँ एक समाधान है:

var a = new{c=1};
var b = new{c=2};
Assert.AreEqual(a, b, string.Format("Not equal {0} {1}", a, b));

5

मैं @StriplingWarrior से सहमत हूं कि यह वास्तव में कम से कम 2 अधिभार पर Assert.AreEqual () विधि के साथ एक बग प्रतीत होता है। जैसा कि स्टीपलिंगवर्यर ने पहले ही बताया है, निम्नलिखित विफल रहता है;

var a = new { c = 1 };
var b = new { c = 2 };
Assert.AreEqual(a, b, "Not equal {0} {1}", a, b);

मैं कोड के उपयोग में थोड़ा और स्पष्ट होने पर आगे इस पर थोड़ा प्रयोग कर रहा हूं। निम्नलिखित या तो काम नहीं करता है;

// specify variable data type rather than "var"...no effect, still fails
Size a = new Size(0, 0);
Size b = new Size(1, 1);
Assert.AreEqual(a, b, "Not equal {0} {1}", a, b);

तथा

// specify variable data type and name the type on the generic overload of AreEqual()...no effect, still fails
Size a = new Size(0, 0);
Size b = new Size(1, 1);
Assert.AreEqual<Size>(a, b, "Not equal {0} {1}", a, b);

यह मुझे सोच में पड़ गया। System.Drawing.Size एक संरचना है। वस्तुओं के बारे में क्या? परम सूची है निर्दिष्ट करें कि के बाद सूची stringसंदेश है params object[]। तकनीकी तौर पर, हाँ structs हैं वस्तुओं ... लेकिन विशेष प्रकार की वस्तुओं की, यानी, मूल्य प्रकार के। मुझे लगता है कि यह वह जगह है जहाँ बग निहित है। यदि हम अपनी स्वयं की वस्तु का उपयोग एक समान उपयोग और संरचना के साथ करते हैं Size, तो निम्नलिखित वास्तव में काम करता है ;

private class MyClass
{
    public MyClass(int width, int height)
        : base()
    { Width = width; Height = height; }

    public int Width { get; set; }
    public int Height { get; set; }
}

[TestMethod]
public void TestMethod1()
{
    var test1 = new MyClass(0, 0);
    var test2 = new MyClass(1, 1);
    Assert.AreEqual(test1, test2, "Show me A [{0}] and B [{1}]", test1, test2);
}

1
समस्या यह नहीं है कि यह है classया नहीं struct, लेकिन क्या ToStringमूल्य में घुंघराले कोष्ठक शामिल हैं जो एक तरह दिखते हैं String.Format
जीन होमिनल

3

मुझे लगता है कि पहला जोर गलत है।

इसके बजाय इसका उपयोग करें:

Assert.AreEqual(struct1, 
                struct2, 
                string.Format("Failed expected {0} actually is {1}", struct1, struct2));

प्रलेखन के अनुसार मैं एक संरचित स्ट्रिंग के साथ AreEqual को कॉल करने में सक्षम होना चाहिए। msdn.microsoft.com/en-us/library/ms243436%28v=vs.100%29.aspx System.Object [] मानकों की एक सरणी जब संदेश स्वरूपण का उपयोग करें:, विशेष प्रकार पैरामीटर।
काइल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.