मैं एक इंटरफ़ेस के बिना एक वर्ग का मज़ाक कैसे कर सकता हूं?


82

मैं विंडोज 7 में C # का उपयोग करके .NET 4.0 पर काम कर रहा हूं।

मैं मॉक का उपयोग करके कुछ तरीकों के बीच संचार का परीक्षण करना चाहता हूं। एकमात्र समस्या यह है कि मैं इसे इंटरफ़ेस लागू किए बिना करना चाहता हूं। क्या यह संभव है?

मैं सिर्फ मॉक ऑब्जेक्ट्स के बारे में बहुत सारे विषय और कुछ ट्यूटोरियल पढ़ता हूं, लेकिन उनमें से सभी इंटरफेस का उपयोग करते हैं, न कि कक्षाओं का। मैंने राइनो और Moq फ्रेमवर्क का उपयोग करने की कोशिश की।


1
यह वास्तव में काटता है कि ये उपकरण विशेष रूप से "IInterfaces" का उपयोग करने के दृष्टिकोण से बनाए गए हैं।
एआर

4
यह मानते हुए बनाया जाता है कि आप इंटरफ़ेस आधारित DI का उपयोग कर रहे हैं। यह इन दिनों एक सुंदर मानक पैटर्न है।
Maess

दुर्भाग्य से, यह पैटर्न अपरिवर्तनीय प्रकार "पैटर्न" के साथ टकराव करता है :(
मैथ्यू वाटसन

जवाबों:


67

बस किसी भी विधि को चिह्नित करें जिसे आपको virtualनिजी होना चाहिए (और निजी नहीं)। तब आप एक नकली बनाने में सक्षम होंगे जो विधि को ओवरराइड कर सकता है।

यदि आप उपयोग करते हैं new Mock<Type>और आपके पास एक पैरामीटर रहित कंस्ट्रक्टर नहीं है, तो आप पैरामीटर को उपरोक्त कॉल के तर्क के रूप में पास कर सकते हैं क्योंकि यह एक प्रकार का हैparam Objects


1
यह मुझे आश्चर्यचकित करता है कि क्या यह आवश्यक है कि मैं जिस कक्षा में नकल करना चाहता हूं, उसके लिए एक इंटरफ़ेस बनाएं। अगर वे एक इंटरफ़ेस नहीं है तो क्या हम केवल मज़ाक करने के लिए ठोस वर्गों का उपयोग नहीं कर सकते हैं?
orad

14
@ जोर वास्तव में, मैं पहले एक वर्ग बनाने के लिए जाता हूं, केवल एक इंटरफ़ेस बनाता हूं अगर मुझे सामान्य कार्यक्षमता को तोड़ने की आवश्यकता होती है।
जस्टिन पिहोनी

फिर आप निर्दिष्ट प्रकार की अपेक्षा किसी वस्तु को कैसे पास करते हैं? अगर मैं एक नकली 'न्यू मॉक <मायटाइप>' बनाऊं और किसी ऑब्जेक्ट को MyType की उम्मीद कर उसे पास करने की कोशिश करूं तो मुझे त्रुटि मिलती है "Mock <MyType> को MyType में कनवर्ट नहीं कर सकता"।
न्यूट्रिनो

2
यदि आपने अपने मॉक को 'var myMock = new Mock <MyType> ()' के रूप में परिभाषित किया है, तो आपको इसे उस वर्ग में शामिल करना होगा, जो आपको mock के रूप में उपयोग करता है।
न्यूट्रिनो

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

22

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

आपके कोड में इंटरफेस बनाने का विरोध क्यों?


107
क्योंकि यह इंटरफेस के टन के साथ कोडबेस को बंद कर देता है, जो कि परीक्षण ढांचे के कुछ तकनीकी सीमा के लिए नहीं है, तो यह पूरी तरह से अनावश्यक होगा?
ब्लूराजा - डैनी पफ्लुगुएफ्ट

9
आपने अभिव्यक्ति "पहुंच से अधिक समझ" सुना है। यह बताता है कि क्यों डेवलपर्स हमेशा शिकायत कर रहे हैं। सी # भाषा को यूनिट टेस्टिंग को ध्यान में रखकर नहीं बनाया गया था। यही कारण है कि व्यर्थ इंटरफेस या आभासी तरीकों की जबरदस्त अव्यवस्था के बिना नकली निर्भरता को इंजेक्ट करना वास्तव में कठिन है। शायद कोई जल्द ही एक ऐसी भाषा का आविष्कार करेगा जो इकाई-परीक्षण के लिए आसान है। तब तक हमारे पास शिकायत करने के लिए कुछ और होगा।
जॉन हेनकेल

13
मुझे यह जानकर खुशी हुई कि मैं केवल वही नहीं हूं जो इंटरफेस और वर्चुअल तरीकों को अव्यवस्था के रूप में देखता है यदि उनका एकमात्र उद्देश्य परीक्षणों की सेवा करना है।
आउआ

13
"केवल उद्देश्य परीक्षणों की सेवा करना है" लेकिन आपके लिए महत्वपूर्ण परीक्षण योग्य कोड नहीं बना रहा है?
MakkyNZ

13
"आपके कोड में इंटरफेस बनाने का विरोध क्यों?" क्योंकि मैंने यह ऑब्जेक्ट नहीं लिखा था, और मेरे पास कोड तक पहुंच नहीं है। मुझे एक बंद वस्तु का मजाक बनाने की जरूरत है जो मैं खुद नहीं करता हूं जो एक इंटरफ़ेस को लागू नहीं करता है।
शॉन वर्ले

16

MoQ के साथ, आप ठोस कक्षाओं का मजाक उड़ा सकते हैं:

var mocked = new Mock<MyConcreteClass>();

लेकिन यह आपको virtualकोड (विधियों और गुणों) को ओवरराइड करने की अनुमति देता है ।


1
मैंने कोशिश की कि, लेकिन जब मैं अपना परीक्षण प्रोजेक्ट चलाता हूं, तो मेरा कार्यक्रम एक अपवाद रखता है: "कक्षा के प्रॉक्सी को त्वरित नहीं कर सकता है" "एक पैरामीटर रहित निर्माता नहीं खोज सका।"
विनीसियस सेगनफ्रेडो

2
बस Mock <> कंस्ट्रक्टर के लिए कंस्ट्रक्टर पैरामीटर पास करें। जैसेnew Mock<MyConcreteClass>(param1, anotherParam, thirdParam, evenMoreParams);
बोहिदार स्टोयनेफ़

1
सिर्फ क्लास के लिए एक इंटरफ़ेस क्यों नहीं बनाया?
रॉबर्ट पेरी

11

मुझे लगता है कि उस वर्ग के लिए एक इंटरफ़ेस बनाना बेहतर है। और इंटरफ़ेस का उपयोग करके एक इकाई परीक्षण बनाएं।

यदि आपके पास उस वर्ग तक पहुंच नहीं है, तो आप उस वर्ग के लिए एक एडाप्टर बना सकते हैं।

उदाहरण के लिए:

public class RealClass
{
    int DoSomething(string input)
    {
        // real implementation here
    }
}

public interface IRealClassAdapter
{
    int DoSomething(string input);
}

public class RealClassAdapter : IRealClassAdapter
{
    readonly RealClass _realClass;

    public RealClassAdapter() => _realClass = new RealClass();

    int DoSomething(string input) => _realClass.DoSomething(input);
}

इस तरह, आप आसानी से IRealClassAdapter का उपयोग करके अपनी कक्षा के लिए नकली बना सकते हैं।

मुझे भरोसा है ये काम करेगा।


4
यह रखरखाव के लिए भयानक है। यदि आप RealClass में एक नई विधि जोड़ना चाहते हैं, तो आपको इसे IReadClassAdapter और RealClassAdapter के साथ भी जोड़ना होगा। कोशिश! बेहतर समाधान यह है कि रियलक्लास में प्रत्येक सार्वजनिक पद्धति में सिर्फ "वर्चुअल" कीवर्ड जोड़ें।
जॉन हेनकेल

12
@ जॉनहेनकेल मैं मान रहा हूं कि रियलक्लास तक हमारी पहुंच नहीं है। इसलिए "आभासी" पद्धति को जोड़ना मेरी राय में एक विकल्प नहीं है। यदि आपके पास वास्तविक वर्ग तक पहुंच है, तो इंटरफ़ेस को सीधे नए वर्ग पर लागू करना बेहतर है, मुझे लगता है कि यह सबसे अच्छा अभ्यास है।
अनंग सतरिया

धन्यवाद। ऐसा लगता है कि बिना किसी पहुंच के कक्षाओं का मजाक उड़ाने का एक कानूनी समाधान है। यहां तक ​​कि यह बहुत "बेवकूफ" कोड है, मुझे "अनुचित वातावरण" में कोड चलाने के लिए इसकी आवश्यकता है
माइकल स्पैनबॉयर

7

मानक मॉकिंग फ्रेमवर्क प्रॉक्सी कक्षाएं बना रहे हैं। यही कारण है कि वे तकनीकी रूप से इंटरफेस और वर्चुअल तरीकों तक सीमित हैं।

यदि आप 'सामान्य' तरीकों का भी मजाक बनाना चाहते हैं, तो आपको एक उपकरण की जरूरत है जो प्रॉक्सी पीढ़ी के बजाय इंस्ट्रूमेंटेशन के साथ काम करे। उदाहरण के लिए एमएस मोल्स और टाइपमॉक ऐसा कर सकते हैं। लेकिन पूर्व में एक भयानक 'एपीआई' है, और बाद वाला वाणिज्यिक है।


क्या हम उस सार्वजनिक पद्धति के साथ सामान्य वर्ग का मजाक उड़ा सकते हैं?
शिवराजिनी

7

यदि आप परीक्षण के तहत कक्षा नहीं बदल सकते हैं, तो एकमात्र विकल्प जो मैं सुझा सकता हूं वह है एमएस फेक https://msdn.microsoft.com/en-us/library/hh549175.aspx का उपयोग करना । हालाँकि, MS Fakes केवल Visual Studio के कुछ संस्करणों में काम करता है।


2

यदि इससे भी बदतर स्थिति में आता है, तो आप एक इंटरफ़ेस और एडेप्टर जोड़ी बना सकते हैं। आप इसके बजाय इंटरफ़ेस का उपयोग करने के लिए कंक्रीटक्लास के सभी उपयोगों को बदल देंगे, और हमेशा उत्पादन कोड में कंक्रीट क्लास के बजाय एडाप्टर को पास करेंगे।

एडेप्टर इंटरफ़ेस को लागू करता है, इसलिए मॉक इंटरफ़ेस को भी लागू कर सकता है।

यह केवल विधि को आभासी बनाने या इंटरफ़ेस को जोड़ने की तुलना में अधिक मचान है, लेकिन अगर आपके पास कंक्रीट वर्ग के लिए स्रोत तक पहुंच नहीं है, तो यह आपको बाइंड से बाहर निकाल सकता है।


1

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

उदाहरण के लिए:

वह सेवा जिसका आप परीक्षण करना चाहते हैं जिसमें आभासी विधियाँ नहीं हैं या इंटरफ़ेस लागू नहीं है

public class ServiceA{

public void A(){}

public String B(){}

}

लहराने के लिए moq

public class ServiceAWrapper : IServiceAWrapper{

public void A(){}

public String B(){}

}

रैपर इंटरफ़ेस

public interface IServiceAWrapper{

void A();

String B();

}

यूनिट टेस्ट में अब आप रैपर का मजाक उड़ा सकते हैं:

    public void A_Run_ChangeStateOfX()
    {
    var moq = new Mock<IServiceAWrapper>();
    moq.Setup(...);
    }

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

अद्यतन: एक वर्ष से अधिक समय से यह उत्तर लेकिन इस वर्ष में मुझे विभिन्न समाधानों के साथ समान परिदृश्यों का सामना करना पड़ा। उदाहरण के लिए, नकली, नकली और स्टब्स बनाने के लिए माइक्रोसॉफ्ट फेक फ्रेमवर्क का उपयोग करना इतना आसान है और बिना किसी इंटरफेस के निजी और संरक्षित तरीकों का भी परीक्षण कर सकते हैं। आप इसे पढ़ सकते हैं: https://docs.microsoft.com/en-us/visualstudio/test/isolating-code-under-test-with-microsoft-fakes?view=vs-2017

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