2013-01-17 10 views
20

मैं पूछ रहा हूं क्योंकि मैं एक मॉकिंग फ्रेमवर्क (मॉकिटो) का उपयोग करने की कोशिश कर रहा हूं जो आपको स्थिर तरीकों का नकल करने की अनुमति नहीं देता है। इसमें देखकर मुझे कुछ ब्लॉग पोस्ट मिल गए हैं, जिसमें कहा गया है कि आपके पास जितनी संभव हो उतनी स्थिर विधियां होनी चाहिए, लेकिन मुझे अपने सिर को लपेटने में कठिनाई क्यों हो रही है। विशेष रूप से वे विधियां जो वैश्विक स्थिति को संशोधित नहीं करती हैं और मूल रूप से सहायक तरीके हैं। उदाहरण के लिए मेरे पास ApiCaller नामक एक वर्ग है जिसमें कई स्थैतिक विधियां हैं। स्थैतिक विधि का उद्देश्य एक HTTP कॉल निष्पादित करना है, हमारे सर्वर द्वारा लौटाए गए किसी भी कस्टम समस्या से निपटने के लिए (पूर्व उपयोगकर्ता लॉग इन नहीं किया गया है) और प्रतिक्रिया वापस कर देता है। सरल बनाने के लिए की तरह कुछ:जावा में स्थिर सहायक विधियों का उपयोग क्यों खराब है?

public class ApiCaller { 
... 
    public static String makeHttpCall(Url url) { 
     // Performs logic to retrieve response and deal with custom server errors 
     ... 
     return response; 
    } 
} 

यह सब मैं क्या करना है का उपयोग करने के कॉल ApiCaller.makeHttpCall(url) अब मैं आसानी से इस तरह एक गैर स्थिर विधि बना सकता है:

public class ApiCaller { 
... 
    public String makeHttpCall(Url url) { 
     // Performs logic to retrieve response and deal with custom server errors 
     ... 
     return response; 
    } 
} 

और उसके बाद इस विधि का उपयोग करने के लिए new ApiCaller().makeHttpCall() पर कॉल करें लेकिन यह सिर्फ अतिरिक्त ओवरहेड जैसा लगता है। क्या कोई यह समझा सकता है कि यह क्यों बुरा है और यदि विधियों को गैर स्थैतिक बनाने के लिए कोई बेहतर समाधान है (केवल कीवर्ड को हटाने के अलावा) ताकि मैं मॉकिंग फ्रेमवर्क का उपयोग करके इन तरीकों को रोक सकूं?

धन्यवाद!

+2

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

+1

@ हॉटिक्सिक्स "सिस्टम स्टफ" के कुछ उदाहरण क्या हैं? इसके अलावा, स्थानीय राज्य के कुछ उदाहरण क्या हैं? क्या फाइल सिस्टम स्थानीय स्थिति के रूप में गिना जाता है? क्या कोई वेबसाइट है? –

+1

"सिस्टम स्टफ" हो सकता है, उदाहरण के लिए, प्रक्रिया भंडारण आंकड़ों को पुनर्प्राप्त करना या दिन या कुछ ऐसा समय लेना। "स्थानीय स्थिति" का तात्पर्य यह है कि विधि 'स्थिर' या कुछ ऐसे में डेटा को छेड़छाड़ कर रही है - यह वास्तव में एक वस्तु है जो होने का नाटक करती है। –

उत्तर

9

स्थैतिक तरीकों के साथ समस्या यह है कि वे नकली के लिए बहुत कठिन हैं जब वे उस सिस्टम के लिए प्रासंगिक नहीं हैं, जिसे आप परीक्षण करने का प्रयास कर रहे हैं। इस कोड की कल्पना कीजिए:

public void systemUnderTest() { 
    Log.connectToDatabaseForAuditing(); 
    doLogicYouWantToTest(); 
} 

connectToDatabaseForAuditing() विधि स्थिर है। आप इस बात की परवाह नहीं करते कि यह विधि आपके द्वारा लिखे जाने वाले परीक्षण के लिए क्या करती है। लेकिन, इस कोड का परीक्षण करने के लिए अब आपको एक उपलब्ध डेटाबेस की आवश्यकता है।

यदि यह स्थिर कोड इस प्रकार दिखाई देगा नहीं थे:

private Logger log; //instantiate in a setter AKA dependency injection/inversion of control 

public void systemUnderTest() { 
    log.connectToDatabaseForAuditing(); 
    doLogicYouWantToTest(); 
} 

और अपने परीक्षण अब एक डेटाबेस के बिना लिखने के लिए तुच्छ होगा:

@Before 
public void setUp() { 
    YourClass yourClass = new YourClass(); 
    yourClass.setLog(new NoOpLogger()); 

} 

//.. your tests 

कि जब ऐसा करने के लिए कोशिश कर रहा कल्पना कीजिए विधि स्थिर है। मैं नामक स्थैतिक चर के लिए लॉगर को संशोधित करने के अलावा वास्तव में किसी तरीके से नहीं सोच सकता हूं, यह सुनिश्चित करने के लिए कि आप किसी डेटाबेस से कनेक्ट नहीं हैं, setUp() में सत्य पर सेट है।

+2

मैं एक मजाकिया दृष्टिकोण से समझता हूं कि स्थैतिक तरीकों के लिए क्यों जरूरी है, लेकिन मैं यह समझने की कोशिश कर रहा हूं कि क्यों बहुत से लोग स्थिर तरीकों का उपयोग कर कह रहे हैं, खराब प्रोग्रामिंग अभ्यास (जैसे http: // ब्लॉग। msdn.com/b/nickmalik/archive/2005/09/06/461404.aspx)। शायद यह एक अच्छा पर्याप्त कारण है, सभी कोड टेस्ट करने योग्य होना चाहिए .. – odiggity

+1

मुझे लगता है कि मैं आपके जैसे ही नाव में हूं। मेरे पास सोलिड सिद्धांतों के साथ समस्या है जो वे समझाते हैं * क्या * लेकिन नहीं * क्यों *।एक बात जो मुझे दिलचस्प लगता है, क्या आपके पास ** सटीक एक ही समस्या ** और ** सटीक एक ही समाधान ** है जो मैंने ऊपर वर्णित किया है यदि आप सिंगलटन पैटर्न के बारे में यह प्रश्न पूछ रहे थे। शायद यह एक संयोग से अधिक है। –

+0

हकीकत में, चाहे यह नकली या नकली के लिए आसान, कठिन, या असंभव है, एक स्थिर विधि पूरी तरह से आपके द्वारा उपयोग किए जा रहे मॉकिंग टूल पर निर्भर करती है। मॉकिटो के साथ, यह संभव नहीं है। मॉकिटो + पावरमोक के साथ यह संभव है, हालांकि बिल्कुल आसान नहीं है (मॉकिटो और पावरमोक एपीआई के कारण दो अलग-अलग एपीआई हैं, और PowerMock API का उपयोग करने के लिए कुछ आवश्यकताओं के कारण भी)। JMockit (मेरा स्वयं का टूल) के साथ, यह आसान है: बस '@Mocked ApiCaller mock' फ़ील्ड/पैरामीटर घोषित करें और फिर' एपीकेलर 'में किसी भी स्थिर विधियों पर अपेक्षाओं को रिकॉर्ड या सत्यापित करें (हालांकि इसमें एक बेहतर डिज़ाइन हो सकता है मामला)। –

2

यह कम मॉड्यूलर है। इसके बजाय आपको एक उदाहरण विधि makeHttpCall() के साथ एक इंटरफ़ेस ApiCaller परिभाषित करना चाहिए ताकि आप भविष्य में अलग-अलग कार्यान्वयन को परिभाषित कर सकें।

कम से कम आपके पास हमेशा इंटरफ़ेस, मूल और मॉक किए गए संस्करण के 2 कार्यान्वयन होंगे।

(नोट: कुछ मजाक चौखटे है कि आपने स्थिर तरीकों नकली करने की अनुमति नहीं है)

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

+0

हालांकि यह आमतौर पर एक अच्छा विचार है, आपको मॉकिटो का उपयोग करते समय ऐसा करने की ज़रूरत नहीं है। आप ठोस वर्ग और नकली ठोस विधि कार्यक्षमता नकली कर सकते हैं। –

+0

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

+0

@DanielKaplan हां, यही वह बात है जिसका मैं मजाकिया संस्करण कहता था। भले ही आप इसे लिखते हैं या ढांचा आपके लिए उत्पन्न करता है, यह अभी भी आपके इंटरफ़ेस का एक * कार्यान्वयन * है –

0

कि जब आप अपने खुद के प्रश्न का उत्तर देने की आवश्यकता हो तो आप उन्हें आसानी से नकल नहीं कर सकते।

विशेष रूप से जब यह कुछ दिखाया गया है है: बनाने एक HTTP कॉल महंगा है, और इकाई के लिए कर रही है कि अपने कोड का परीक्षण कोई मतलब नहीं है बचाने – कि एकीकरण परीक्षण के लिए।

यूनिट परीक्षणों को HTTP कॉल से ज्ञात प्रतिक्रियाएं (और प्रतिक्रिया कोड) की आवश्यकता होती है, अगर आप किसी ऐसे नेटवर्क का उपयोग करके अन्य सेवा को कॉल कर रहे हैं, तो आप ऐसा नहीं कर सकते हैं।

1

निजी स्टेटिक सहायक विधियां खराब नहीं हैं, असल में, वे वास्तव में बड़े निगम में पसंद करते हैं जहां मैं काम करता हूं। और मैं उन सभी के साथ मॉकिटो का उपयोग करता हूं, जो स्थिर सहायक विधि को कॉल करने वाले तरीकों से पहुंचे हैं।

कंपाइलर एक स्थिर सहायक विधि का इलाज कैसे करता है इसमें थोड़ा अंतर है। बनाए गए बाइट कोड के परिणामस्वरूप invokestatic निर्देश होगा, और यदि आप स्थैतिक को हटा देते हैं तो परिणाम अन्य निर्देशों में से एक होगा, जैसे कि invokespecial। अंतर यह है कि invokestatic वर्ग को विधि तक पहुंचने के लिए लोड करता है, जहां invokespecial पहले ऑब्जेक्ट को ढेर से पॉप करता है। तो थोड़ा सा प्रदर्शन लाभ हो सकता है (शायद नहीं)।

संबंधित मुद्दे