जब निर्माता के पास पैरामीटर हैं, तो Moq के साथ मॉकिंग ऑब्जेक्ट


92

मुझे लगता है मैं moq का उपयोग कर नकली करने की कोशिश कर रहा हूँ एक वस्तु है। ऑब्जेक्ट के निर्माता के लिए आवश्यक पैरामीटर हैं:

public class CustomerSyncEngine {
    public CustomerSyncEngine(ILoggingProvider loggingProvider, 
                              ICrmProvider crmProvider, 
                              ICacheProvider cacheProvider) { ... }
}

अब मैं moq के v3 "सेटअप" या v4 "Mock.Of" सिंटैक्स का उपयोग करके इस ऑब्जेक्ट के लिए मॉक बनाने की कोशिश कर रहा हूं, लेकिन यह पता नहीं लगा सकता ... मैं जो भी कोशिश कर रहा हूं वह मान्य नहीं है। यहाँ मेरे पास अभी तक क्या है, लेकिन अंतिम पंक्ति मुझे एक वास्तविक वस्तु दे रही है, नकली नहीं। मैं ऐसा कर रहा हूं इसका कारण यह है कि मेरे पास कस्टमर सिनसिंगबाइन पर तरीके हैं जिन्हें मैं सत्यापित करना चाहता हूं कि उन्हें बुलाया जा रहा है ...

// setup
var mockCrm = Mock.Of<ICrmProvider>(x => x.GetPickLists() == crmPickLists);
var mockCache = Mock.Of<ICacheProvider>(x => x.GetPickLists() == cachePickLists);
var mockLogger = Mock.Of<ILoggingProvider>();

// need to mock the following, not create a real class like this...
var syncEngine = new CustomerSyncEngine(mockLogger, mockCrm, mockCache);

क्या आप एक नमूना विधि प्रदान कर सकते हैं जिसे आप सत्यापित करना चाहते हैं?
साइरन

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

जवाबों:


34

अंतिम पंक्ति आपको एक वास्तविक उदाहरण दे रही है, क्योंकि आप नए कीवर्ड का उपयोग कर रहे हैं, न कि CustomerSyncEngine का मजाक उड़ा रहे हैं।

आपको उपयोग करना चाहिए Mock.Of<CustomerSyncEngine>()

मॉकिंग कंक्रीट प्रकारों के साथ एकमात्र समस्या यह है कि Moq को सार्वजनिक डिफ़ॉल्ट निर्माणकर्ता (कोई मापदंडों के साथ) की आवश्यकता नहीं होगी या आपको निर्माता arg विनिर्देशन के साथ Moq बनाने की आवश्यकता होगी। http://www.mockobjects.com/2007/04/test-smell-mocking-concrete-classes.html

सबसे अच्छी बात यह है कि अपनी कक्षा पर सही क्लिक करें और निकालें इंटरफ़ेस चुनें।


3
समस्या के संबंध में, एक विकल्प AutoMocking कंटेनर का उपयोग करना है। मेरा पसंदीदा मशीन है। मशीन के साथ संयोजन के रूप में बनाया जाता है। एक स्वचालित कंटेनर का उपयोग करके छोटे सतह क्षेत्रों का परीक्षण करना आसान हो जाता है। मान लीजिए कि एंड्रयू को एक विधि का परीक्षण करने की आवश्यकता है CustomerSyncEngineजिसमें केवल ICrmProviderपारंपरिक मॉकिंग कार्यान्वयन के साथ उपयोग होता है, जो सभी 3 इंटरफेस के लिए प्रदान किया जाना चाहिए, जबकि एक ऑटमॉकिंग कंटेनर आपको केवल एक प्रदान करने की अनुमति देगा।
क्रिस मैरिक

73

अंतिम पंक्ति को बदलें

var syncEngine = new Mock<CustomerSyncEngine>(mockLogger, mockCrm, mockCache).Object;

और यह काम करना चाहिए


3
यकीन नहीं होता कि यह टिप्पणी मेरे उत्तर पर कैसे लागू होती है?
सुहास

2
क्योंकि यह मॉकलॉगर के रूप में एक संकलित त्रुटि का कारण होगा और अन्य एक अपवाद को फेंक देंगे कि उनके पास एक वस्तु संपत्ति नहीं है
जस्टिन पिहोनी

2
क्योंकि ओपी Mock.Of <T> () का उपयोग कर लकड़हारा, crm, और कैश प्रकारों के नकली बनाने के लिए, वापस की गई वस्तु को T के रूप में लौटाया जाता है, न कि Mock <T> के रूप में। इसलिए, MockLogger.Object आदि की जरूरत नहीं है, जब उन्हें CustomerSyncEngine के Mock में दिया जाए और जैसा कि @JustinPihony ने उल्लेख किया है, आपको एक डिज़ाइन समय त्रुटि दिखाना चाहिए।
जोश गस्ट

1
@ ल्हास उनके नहीं होना चाहिएnew Mock<CustomerSyncEngine>(new object[]{mockLogger, mockCrm, mockCache}).Object;
गिरि

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