EasyMock या Mockito जैसे लोकप्रिय जावा मॉकिंग फ्रेमवर्क में से एक defprotocol
के साथ परिभाषित क्लोजर प्रोटोकॉल का नकल करने के लिए उपयोग किया जा सकता है? यदि हां, तो कैसे?मॉकिंग क्लोजर प्रोटोकॉल
उत्तर
आप किसी भी नकली पुस्तकालय का उपयोग कर प्रोटोकॉल नकल करने में सक्षम होना चाहिए। कवर के तहत, प्रत्येक प्रोटोकॉल जावा इंटरफ़ेस का कार्यान्वयन विवरण के रूप में उपयोग करता है, और आप बस उस इंटरफ़ेस को नकल कर सकते हैं।
उसने कहा, ऐसा मत करो! जावा में मॉकिंग प्रतिबिंब, सुरक्षा स्तर, अंतिम कक्षाएं इत्यादि के कारण बेहद जटिल है। जब भी आप एक क्लोजर ऑब्जेक्ट चाहते हैं जो प्रोटोकॉल लागू करता है, तो बस reify पर कॉल करें, उदा।
(defprotocol Foo (method-a [_]) (method-b [_]))
-> Foo
(let [stub (reify Foo (method-a [_] :stubbed))]
(method-a stub))
-> :stubbed
ध्यान दें कि आपको उन तरीकों को रोकने की आवश्यकता नहीं है जिन्हें आप कॉल करने की योजना नहीं बनाते हैं।
ऐसा लगता है कि मिडजे के हाल के संस्करण इस कार्यक्षमता को काफी अच्छी तरह से प्रदान करते हैं।
सबसे पहले, मुझे यह ध्यान रखना होगा कि बड़े पैमाने पर प्रोग्रामों को विभाजित करते समय इस प्रकार का मॉकिंग बहुत उपयोगी होता है (उदाहरण के लिए स्टुअर्ट सिएरा के component library जैसे पुस्तकालयों के साथ निर्भरता इंजेक्शन के माध्यम से इकट्ठा किया जाता है)। मैं कुछ घटक है कि एक वैचारिक घटक मैं निश्चित रूप से एक परीक्षण ढांचे चाहते में पक्ष प्रभाव कार्यों का एक सेट को अलग कर रखी है, तो है कि मुझे एक स्टैंड में घटक इंजेक्षन करने देगा ताकि मैं कर सकते हैं:
- लिखें कोड है कि इससे पहले कि घटक भी मौजूद है (टॉप-डाउन) घटक का उपयोग करता है।
- परीक्षण कार्य जो घटक के वास्तविक कार्यान्वयन से अलगाव में उस घटक का उपयोग करते हैं।
आप मॉकिटो या कुछ अन्य लाइब्रेरी का उपयोग कर सकते हैं, लेकिन मैं मानता हूं कि ऐसा समाधान विशेष रूप से सुरुचिपूर्ण नहीं होगा।
दुर्भाग्य से, प्रोटोकॉल और रिकॉर्ड कक्षाएं कि Midje कार्यों के रूप में के रूप में आसानी को हैक नहीं कर सकते हैं उत्पन्न ... ताकि आप अपने कोड में थोड़ा सा संशोधन करना है:
(defrecord-openly SideEffectThing [connection]
ISideEffect
(persist [this thing] :unfinished)
(read [this] :unfinished)
)
कैसे इस संशोधन करने के बारे में जानकारी के लिए Midje's documentation on production mode देखें अपने उत्पादन रनटाइम को प्रभावित नहीं करते हैं।
(fact "you can test in terms of a record's methods"
(let [obj (->SideEffectThing :fake-connection)]
(user-of-side-effect-thing obj) => 0
(provided
(read obj) => -1)
)
)
आप, ज़ाहिर है, यहाँ एक उत्पादन प्रकार पर निर्भर रहने से बच सकता है:
defrecord-openly के साथ अपने घटक परिभाषित करके, आप Midje के "प्रदान की" क्रियाविधि का उपयोग घटक के तरीकों के व्यवहार निर्दिष्ट करने की क्षमता हासिल (जो मैं वकालत करता हूं), और अपने उत्पादन कोड में खुलेआम खुलेआम मिर्च से बचने से बचें। इस मामले में, बस अपने टेस्ट कोड में SideEffectThing (जैसा ऊपर लिखा गया है) को ले जाएं। फिर एप्लिकेशन में आपका घटक सिस्टम वास्तविक घटक में प्लग कर सकता है, लेकिन आपके परीक्षण इस अनुपूरक परीक्षण संस्करण के खिलाफ लिखे जा सकते हैं।
पूरा होने के लिए, मैं उपर्युक्त समाधान के साथ समकक्ष जावा मॉकिटो कोड की तुलना करूंगा। जावा में:
interface ISideEffect { int read(); void write(Object something); }
class SideEffectThing implements ISideEffect { ... }
// in test sources:
public class SomeOtherComponentSpec {
private ISideEffect obj;
@Before
public void setup() { obj = mock(ISideEffect.class); }
@Test
public void does_something_useful() {
when(obj.read()).thenReturn(-1);
OtherComponent comp = new OtherComponent(obj);
int actual = comp.doSomethingUseful();
assertEquals(0, actual);
verify(obj).read();
}
इस जावा समाधान घटक बाहर का मजाक उड़ाता है, कि घटक के लिए आवश्यक व्यवहार निर्दिष्ट करता है, और उसके बाद न केवल जांच करता है कि घटक ही ठीक से काम करता, लेकिन यह भी घटक कॉल पर निर्भर है कि पढ़ने के लिए() किसी तरह।मॉकिटो तर्कों (और कैप्चर) पर पैटर्न मिलान का भी समर्थन करता है ताकि विश्लेषण किया जा सके कि घटक का उपयोग कैसे किया जाता है।
Midje उपरोक्त उदाहरण इस बात का बहुत करता है, और एक बहुत स्पष्ट रूप में। यदि आप इंगित करते हैं (प्रदत्त खंड में) कि फ़ंक्शन को विशिष्ट तर्कों के साथ बुलाया जाता है, तो परीक्षण विफल होने पर विफल हो जाएगा। यदि आप निर्दिष्ट करते हैं कि फ़ंक्शन को एक से अधिक बार कहा जाता है (और यह नहीं है), तो यह एक विफलता है। उदाहरण के लिए, इंगित करने के लिए पढ़ने के लिए 3 बार बुलाया जाएगा और विभिन्न मान चाहिए:
(fact "you can test in terms of a record's methods"
(let [obj (->SideEffectThing :fake-connection)]
(user-of-side-effect-thing obj) => 0
(provided
(read obj) => -1
(read obj) => 6
(read obj) => 99
)
)
)
इंगित करता है कि आप तीन बार के नाम से जाना पढ़ उम्मीद है, और यह मूल्यों की निर्दिष्ट अनुक्रम लौट जाना चाहिए। अधिक जानकारी के लिए docs on prerequisites देखें, जिसमें प्रदान किए गए एक फ़ंक्शन स्पेक पर सटीक संख्या निर्दिष्ट करने के तरीके और फ़ंक्शन को इंगित करने के तरीके को कभी भी नहीं कहा जाता है।
यह स्टबिंग है। मज़ाक करने के बारे में क्या? आप _idiomatically_ अपेक्षाओं को परिभाषित और सत्यापित कैसे करेंगे? –
मैं @ डेडिन से सहमत हूं। ऐसा लगता है कि व्यवहार के बारे में दावा बताते हुए प्रथम श्रेणी के समर्थन के साथ-साथ यह सत्यापित करने के लिए कि वे घटित हुए हैं, बस स्टबिंग के साथ मैला होने जा रहे हैं ... उदा। सत्यापित करें कि प्रोटोकॉल.एफ 3 बार बुलाया गया था ... क्या, मैं एक var बना देता हूं, इसे बदलता हूं, फिर मान की जांच करता हूं? यह बहुत घोषणा नहीं है। निश्चित रूप से किसी ने कुछ कम लिखा है ताकि इसे थोड़ा कम बॉयलरप्लेट की आवश्यकता हो। –