मुझे संदेश के साथ अपवाद क्यों मिल रहा है "गैर-आभासी पर अमान्य सेटअप (VB में सदस्य के रूप में देखने योग्य) ..."?


176

मेरे पास एक इकाई परीक्षण है जहां मुझे एक गैर-आभासी पद्धति का मजाक उड़ाना पड़ता है जो एक बूल प्रकार देता है

public class XmlCupboardAccess
{
    public bool IsDataEntityInXmlCupboard(string dataId,
                                          out string nameInCupboard,
                                          out string refTypeInCupboard,
                                          string nameTemplate = null)
    {
        return IsDataEntityInXmlCupboard(_theDb, dataId, out nameInCupboard, out refTypeInCupboard, nameTemplate);
    }
}

इसलिए मेरे पास XmlCupboardAccessक्लास की एक नकली वस्तु है और मैं अपने परीक्षण के मामले में इस विधि के लिए मॉक सेटअप करने की कोशिश कर रहा हूं जैसा कि नीचे दिखाया गया है

[TestMethod]
Public void Test()
{
    private string temp1;
    private string temp2;
    private Mock<XmlCupboardAccess> _xmlCupboardAccess = new Mock<XmlCupboardAccess>();
    _xmlCupboardAccess.Setup(x => x.IsDataEntityInXmlCupboard(It.IsAny<string>(), out temp1, out temp2, It.IsAny<string>())).Returns(false); 
    //exception is thrown by this line of code
}

लेकिन यह रेखा अपवाद को फेंकती है

Invalid setup on a non-virtual (overridable in VB) member: 
x => x.IsDataEntityInXmlCupboard(It.IsAny<String>(), .temp1, .temp2, 
It.IsAny<String>())

किसी भी सुझाव कैसे इस अपवाद के आसपास पाने के लिए?


आपके परीक्षण में क्या निर्भर करता है XmlCupboardAccess?
प्रेस्टन गिलोट

9
इसका सरल .. आपको इसे चिह्नित करने की आवश्यकता है virtual। Moq एक ठोस प्रकार का मजाक नहीं कर सकता है जो इसे ओवरराइड नहीं कर सकता।
साइमन व्हाइटहेड

जवाबों:


265

Moq गैर-आभासी तरीकों और सीलबंद कक्षाओं का मजाक नहीं उड़ा सकता। मॉक ऑब्जेक्ट का उपयोग करके एक परीक्षण चलाने के दौरान, MOQ वास्तव में एक इन-मेमोरी प्रॉक्सी प्रकार बनाता है जो आपके "XmlCupboardAccess" से विरासत में मिलता है और उन व्यवहारों को ओवरराइड करता है जिन्हें आपने "सेटअप" विधि में सेट किया है। और जैसा कि आप C # में जानते हैं, आप कुछ को केवल तभी ओवरराइड कर सकते हैं जब इसे वर्चुअल के रूप में चिह्नित किया जाए जो जावा के मामले में नहीं है। जावा हर गैर-स्थैतिक विधि को डिफ़ॉल्ट रूप से आभासी मानता है।

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

: अंत में, वहाँ की तरह चौखटे हैं TypeMock और JustMock जो आईएल के साथ सीधे काम और इसलिए गैर आभासी तरीकों नकली कर सकते हैं। दोनों हालांकि, वाणिज्यिक उत्पाद हैं।


59
इस तथ्य पर +1 कि आपको केवल इंटरफेस को मॉक करना चाहिए। यह प्रश्न हल हो गया कि मैं क्या में चल रहा था, क्योंकि मैंने गलती से क्लास का मजाक उड़ाया था न कि अंतर्निहित इंटरफेस का।
पॉल रफ़

1
न केवल यह समस्या को हल करता है, बल्कि आपके सभी वर्गों के लिए इंटरफेस का उपयोग करने के लिए अच्छा अभ्यास है जिन्हें परीक्षण की आवश्यकता है। Moq अनिवार्य रूप से आपको अच्छा डिपेंडेंसी इनवर्सन करने के लिए मजबूर कर रहा है, जहाँ कुछ अन्य नकली रूपरेखाएँ आपको इस सिद्धांत के इर्द-गिर्द आने देती हैं।
Xipooo

क्या इस सिद्धांत का उल्लंघन माना जाएगा, यदि मेरे पास नकली कार्यान्वयन है, उदाहरण के लिए, मेरे इंटरफ़ेस का FakePeopleRepository, जैसे, IPeopleRepository, और मैं नकली कार्यान्वयन का मज़ाक उड़ा रहा हूं? मुझे लगता है कि IoC अभी भी संरक्षित है क्योंकि मेरे परीक्षण सेटअप में मुझे अपने सेवा वर्ग के लिए नकली ऑब्जेक्ट को पास करना होगा जो इसके निर्माता में इंटरफ़ेस लेता है।
पाज़

1
@paz MOQ के उपयोग का पूरा बिंदु नकली कार्यान्वयन से बचने के लिए है। अब विचार करें कि नकली कार्यान्वयन के कितने प्रकार आपको सीमा की स्थिति आदि की जांच करने की आवश्यकता होगी। सिद्धांत रूप में, हाँ, आप नकली कार्यान्वयन का मजाक उड़ा सकते हैं। लेकिन व्यावहारिक रूप से यह एक कोड गंध की तरह लगता है।
अमोल

ध्यान दें कि यह त्रुटि वास्तव में इंटरफेस पर विस्तार विधियों के साथ हो सकती है, जो भ्रामक हो सकती है।
डैन पेंट्री

34

किसी की भी मदद करने में जो मेरे जैसी ही समस्या थी, मैंने गलती से इंटरफ़ेस के बजाय कार्यान्वयन प्रकार को गलत कर दिया

var mockFileBrowser = new Mock<FileBrowser>();

के बजाय

var mockFileBrowser = new Mock<IFileBrowser>();

5

कृपया देखें कि जिस संपत्ति का मैं मजाक करना चाहता हूं वह आभासी क्यों है?

आपको रैपर इंटरफ़ेस लिखना पड़ सकता है या संपत्ति को आभासी / सार के रूप में चिह्नित करना पड़ सकता है क्योंकि Moq एक प्रॉक्सी क्लास बनाता है जो कॉल को इंटरसेप्ट करने और आपके कस्टम मानों को वापस करने के लिए उपयोग करता है जो आप .Returns(x)कॉल में डालते हैं ।


5

कंक्रीट क्लास का मज़ाक करने के बजाय आपको उस क्लास इंटरफ़ेस का मज़ाक उड़ाना चाहिए। XmlCupboardAccess वर्ग से इंटरफ़ेस निकालें

public interface IXmlCupboardAccess
{
    bool IsDataEntityInXmlCupboard(string dataId, out string nameInCupboard, out string refTypeInCupboard, string nameTemplate = null);
}

और के बजाय

private Mock<XmlCupboardAccess> _xmlCupboardAccess = new Mock<XmlCupboardAccess>();

में बदलो

private Mock<IXmlCupboardAccess> _xmlCupboardAccess = new Mock<IXmlCupboardAccess>();

3

आपको यह त्रुटि तब भी होगी जब आप सत्यापित कर रहे हैं कि इंटरफ़ेस का एक्सटेंशन तरीका कहा जाता है।

उदाहरण के लिए यदि आप मजाक कर रहे हैं:

var mockValidator = new Mock<IValidator<Foo>>();
mockValidator
  .Verify(validator => validator.ValidateAndThrow(foo, null));

आपको समान अपवाद मिलेगा क्योंकि इंटरफ़ेस .ValidateAndThrow()पर एक एक्सटेंशन IValidator<T>है।

public static void ValidateAndThrow<T>(this IValidator<T> validator, T instance, string ruleSet = null)...


-12

कोड:

private static void RegisterServices(IKernel kernel)
{
    Mock<IProductRepository> mock=new Mock<IProductRepository>();
    mock.Setup(x => x.Products).Returns(new List<Product>
    {
        new Product {Name = "Football", Price = 23},
        new Product {Name = "Surf board", Price = 179},
        new Product {Name = "Running shose", Price = 95}
    });

    kernel.Bind<IProductRepository>().ToConstant(mock.Object);
}        

लेकिन अपवाद देखें।


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