मॉकिटो मैचर्स स्टैटिक मेथड हैं और उन तरीकों पर कॉल करते हैं, जो कॉल टू और के दौरान बहस के लिए खड़े होते हैं ।when
verify
हैमरेस्ट मैचर्स (संग्रहीत संस्करण) (या हैमरेस्ट-स्टाइल मैचर्स) स्टेटलेस, सामान्य-उद्देश्य ऑब्जेक्ट इंस्टेंस हैं जो लागू करते हैं Matcher<T>
और एक विधि को उजागर करते हैं matches(T)
जो ऑब्जेक्ट मैचर्स के मानदंडों से मेल खाता है। वे साइड इफेक्ट से मुक्त होने का इरादा रखते हैं, और आम तौर पर नीचे दिए गए जैसे कथनों में उपयोग किया जाता है।
/* Mockito */ verify(foo).setPowerLevel(gt(9000));
/* Hamcrest */ assertThat(foo.getPowerLevel(), is(greaterThan(9000)));
मॉकिटो मैचर्स मौजूद हैं, हैमरेस्ट-शैली के मैचर्स से अलग, ताकि मिलान अभिव्यक्तियों का वर्णन सीधे विधि इनवॉइस में फिट हो : मॉकिटो मैचर्स वापस लौटते हैं T
जहां हैमरेस्ट मैचर तरीके मैचर ऑब्जेक्ट्स (प्रकार का Matcher<T>
) वापस करते हैं।
Mockito matchers जैसे स्थिर तरीकों के माध्यम से लागू कर रहे हैं eq
, any
, gt
, और startsWith
पर org.mockito.Matchers
और org.mockito.AdditionalMatchers
। एडाप्टर्स भी हैं, जो मॉकिटो संस्करणों में बदल गए हैं:
- मॉकिटो 1.x के लिए,
Matchers
कुछ कॉल में (जैसे intThat
या जैसे argThat
) मॉकिटो मैचर्स होते हैं जो हैमरेस्ट मैचर्स को सीधे मापदंडों के रूप में स्वीकार करते हैं। ArgumentMatcher<T>
विस्तारित org.hamcrest.Matcher<T>
, जिसका उपयोग आंतरिक हैमरेस्ट प्रतिनिधित्व में किया गया था और यह किसी भी प्रकार के मॉकिटो मैचर के बजाय हैमरेस्ट मैचर बेस क्लास था ।
- मॉकिटो 2.0+ के लिए, मॉकिटो का अब हैमरेस्ट पर सीधा निर्भरता नहीं है।
Matchers
कॉल किए गए ऑब्जेक्ट्स के रूप में intThat
या ऐसे ऑब्जेक्ट्स को argThat
रैप करते ArgumentMatcher<T>
हैं जो अब लागू org.hamcrest.Matcher<T>
नहीं होते हैं लेकिन समान तरीकों से उपयोग किए जाते हैं। Hamcrest एडेप्टर जैसे argThat
और intThat
अभी भी उपलब्ध हैं, लेकिन MockitoHamcrest
इसके बजाय चले गए हैं ।
चाहे मैचर्स हैमरेस्ट हों या बस हैमरेस्ट-स्टाइल, उन्हें इस तरह से अनुकूलित किया जा सकता है:
/* Mockito matcher intThat adapting Hamcrest-style matcher is(greaterThan(...)) */
verify(foo).setPowerLevel(intThat(is(greaterThan(9000))));
उपरोक्त कथन में: foo.setPowerLevel
एक विधि है जो एक को स्वीकार करती है int
। is(greaterThan(9000))
एक रिटर्न देता है Matcher<Integer>
, जो एक setPowerLevel
तर्क के रूप में काम नहीं करेगा । Mockito मिलान intThat
लपेटता है कि Hamcrest शैली Matcher और रिटर्न एक int
ऐसा कर सकते हैं एक तर्क के रूप दिखाई देते हैं; gt(9000)
उदाहरण के कोड की पहली पंक्ति में, मॉकिटो मैचर्स उस संपूर्ण अभिव्यक्ति को एक कॉल में लपेट देंगे।
मैचर्स क्या करते / करते हैं
when(foo.quux(3, 5)).thenReturn(true);
जब तर्क मिलानकर्ताओं का उपयोग नहीं करते हैं, तो मॉकिटो आपके तर्क मूल्यों को रिकॉर्ड करता है और उनकी तुलना उनके equals
तरीकों से करता है।
when(foo.quux(eq(3), eq(5))).thenReturn(true); // same as above
when(foo.quux(anyInt(), gt(5))).thenReturn(true); // this one's different
जब आप किसी माचिस को पसंद करते हैं any
या gt
(इससे बड़ा) कहते हैं, तो मॉकिटो एक माचिस वस्तु को संग्रहित करता है जिसके कारण मॉकिटो उस समानता को छोड़ देता है और आपकी पसंद के मैच को लागू करता है। मामले में argumentCaptor.capture()
यह एक मिलानकर्ता को संग्रहीत करता है जो बाद के निरीक्षण के लिए इसके तर्क को बचाता है।
मिलानकर्ता डमी मानों जैसे कि शून्य, खाली संग्रह, या वापस लौटाते हैं null
। मॉकिटो एक सुरक्षित, उपयुक्त डमी मूल्य वापस करने की कोशिश करता है, जैसे कि 0 anyInt()
या any(Integer.class)
उसके List<String>
लिए खाली anyListOf(String.class)
। प्रकार के क्षरण के कारण, हालांकि, मॉकिटो में किसी भी मूल्य को वापस करने के लिए टाइप जानकारी का अभाव है, लेकिन या जिसके null
लिए एक NullPointerException कारण हो सकता है यदि "ऑटो-अनबॉक्स" को एक आदिम मान देने की कोशिश की जाती है।any()
argThat(...)
null
जैसे matchers eq
और gt
ले पैरामीटर मान; आदर्श रूप से, स्टबिंग / सत्यापन शुरू होने से पहले इन मूल्यों की गणना की जानी चाहिए। दूसरे कॉल को मॉकिंग के बीच में एक मॉक कॉल करना स्टबिंग के साथ हस्तक्षेप कर सकता है।
मिलान विधियों का उपयोग रिटर्न मान के रूप में नहीं किया जा सकता है; उदाहरण के लिए, वाक्यांश thenReturn(anyInt())
या thenReturn(any(Foo.class))
मॉकिटो में कोई रास्ता नहीं है । मॉकिटो को यह जानने की जरूरत है कि स्टबिंग कॉल में वापस आने के लिए कौन सा उदाहरण है, और आपके लिए एक मनमाना रिटर्न मान का चयन नहीं करेगा।
कार्यान्वयन का विवरण
मिलान ArgumentMatcherStorage नामक एक वर्ग में निहित स्टैक में हैमरेस्ट-स्टाइल ऑब्जेक्ट मैचर्स के रूप में संग्रहीत किए जाते हैं । MockitoCore और Matchers प्रत्येक का खुद का एक ThreadSafeMockingProgress उदाहरण है, जिसमें स्टेटिक रूप से एक थ्रॉक्लॉक होल्डिंग MockingProgress इंस्टेंस है। यह एक MockingProgressImpl है जो एक ठोस ArgumentMatcherStorageImpl रखती है । नतीजतन, मॉक और मैचर स्टेट स्थिर है लेकिन मॉकिटो और मैचर्स वर्गों के बीच लगातार थ्रेड-स्कोप किया जाता है।
अधिकांश मिलानकर्ता कॉल केवल इस स्टैक में जोड़ते हैं and
,or
not
जैसे मैचर्स और , के लिए एक अपवाद । यह पूरी तरह से जावा के मूल्यांकन क्रम से मेल खाता है (और निर्भर करता है) , जो एक तेज तरीके को लागू करने से पहले बाएं से दाएं तर्कों का मूल्यांकन करता है:
when(foo.quux(anyInt(), and(gt(10), lt(20)))).thenReturn(true);
[6] [5] [1] [4] [2] [3]
यह करेगा:
anyInt()
स्टैक में जोड़ें ।
gt(10)
स्टैक में जोड़ें ।
lt(20)
स्टैक में जोड़ें ।
- निकालें
gt(10)
और lt(20)
जोड़ें and(gt(10), lt(20))
।
- कॉल करें
foo.quux(0, 0)
, जो (जब तक अन्यथा स्टब न हो) डिफ़ॉल्ट मान लौटाता है false
। quux(int, int)
सबसे हालिया कॉल के रूप में आंतरिक रूप से मॉकिटो निशान ।
- कॉल
when(false)
, जो अपने तर्क को खारिज करता है और quux(int, int)
5. पहचान की गई स्टब विधि को तैयार करता है । केवल दो वैध अवस्थाएं स्टैक लंबाई 0 (समानता) या 2 (मैचर्स) के साथ हैं, और स्टैक पर दो मैचर्स हैं (चरण 1 और 4), इसलिए मॉकिटो any()
अपने पहले तर्क के लिए और and(gt(10), lt(20))
दूसरे तर्क के लिए एक मिलानकर्ता के साथ विधि को स्टब्स करता है और स्टैक को साफ़ करता है।
यह कुछ नियमों को प्रदर्शित करता है:
मॉकिटो quux(anyInt(), 0)
और के बीच अंतर नहीं बता सकता है quux(0, anyInt())
। वे दोनों quux(0, 0)
स्टैक पर एक इंट मैचर के साथ एक कॉल की तरह दिखते हैं । नतीजतन, यदि आप एक मिलानकर्ता का उपयोग करते हैं, तो आपको सभी तर्कों का मिलान करना होगा।
कॉल ऑर्डर केवल महत्वपूर्ण नहीं है, यह वही है जो यह सब काम करता है । वैरिएबल को वेरिएबल्स में निकालना आमतौर पर काम नहीं करता है, क्योंकि यह आमतौर पर कॉल ऑर्डर बदलता है। विधियों के लिए मैचर्स निकालना, हालांकि, महान काम करता है।
int between10And20 = and(gt(10), lt(20));
/* BAD */ when(foo.quux(anyInt(), between10And20)).thenReturn(true);
// Mockito sees the stack as the opposite: and(gt(10), lt(20)), anyInt().
public static int anyIntBetween10And20() { return and(gt(10), lt(20)); }
/* OK */ when(foo.quux(anyInt(), anyIntBetween10And20())).thenReturn(true);
// The helper method calls the matcher methods in the right order.
स्टैक अक्सर बदलता है कि मॉकिटो इसे बहुत सावधानी से पुलिस नहीं कर सकता है। यह केवल स्टैक की जांच कर सकता है जब आप मॉकिटो या मॉक के साथ बातचीत करते हैं, और मैचर्स को यह जानने के बिना स्वीकार करना पड़ता है कि क्या वे तुरंत उपयोग किए जाते हैं या गलती से छोड़ दिए जाते हैं। सिद्धांत रूप में, स्टैक हमेशा कॉल करने के लिए when
या के बाहर खाली होना चाहिए verify
, लेकिन मॉकिटो स्वचालित रूप से जांच नहीं कर सकता है। आप मैन्युअल रूप से देख सकते हैं Mockito.validateMockitoUsage()
।
कॉल करने के लिए when
, मॉकिटो वास्तव में प्रश्न में विधि को कॉल करता है, जो एक अपवाद को फेंक देगा यदि आपने अपवाद फेंकने के लिए विधि (या गैर-शून्य या गैर-शून्य मानों की आवश्यकता होती है) को फेंक दिया है।
doReturn
और doAnswer
(आदि) वास्तविक विधि को लागू नहीं करते हैं और अक्सर एक उपयोगी विकल्प होते हैं।
यदि आपने स्टबिंग के बीच एक मॉक विधि को बुलाया था (जैसे एक eq
माचिस के लिए एक उत्तर की गणना करने के लिए ), तो मॉकिटो उस कॉल के बजाय स्टैक की लंबाई की जांच करेगा , और संभवत: विफल हो जाएगा।
यदि आप कुछ बुरा करने की कोशिश करते हैं, जैसे कि अंतिम विधि को रोकने / सत्यापित करने के लिए , मॉकिटो वास्तविक विधि को बुलाएगा और स्टैक पर अतिरिक्त मिलान भी छोड़ देगा । final
विधि कॉल एक अपवाद फेंक नहीं सकते हैं, लेकिन आप एक मिल सकता है InvalidUseOfMatchersException आवारा matchers एक नकली के साथ जब आप अगली सहभागिता से।
सामान्य समस्यायें
अमान्य यूओफ़ऑफ़मैटर्स अपवाद :
जांचें कि हर एक तर्क में बिल्कुल एक मिलानकर्ता कॉल है, यदि आप मैचर्स का उपयोग करते हैं, और यह कि आपने किसी मिलानकर्ता को कॉल when
या verify
कॉल के बाहर उपयोग नहीं किया है । मैचर्स को कभी भी स्टेबल रिटर्न वैल्यू या फील्ड / वैरिएबल के रूप में इस्तेमाल नहीं करना चाहिए।
जांचें कि आप एक मॉक को एक मिलान तर्क प्रदान करने के हिस्से के रूप में नहीं बुला रहे हैं।
जांचें कि आप एक मिलानकर्ता के साथ अंतिम विधि को स्टब / सत्यापित करने का प्रयास नहीं कर रहे हैं। यह स्टैक पर एक मिलानकर्ता को छोड़ने का एक शानदार तरीका है, और जब तक कि आपकी अंतिम विधि एक अपवाद नहीं फेंकती है, यह केवल एक बार हो सकता है जब आपको पता चलता है कि आप जिस विधि का मजाक उड़ा रहे हैं वह अंतिम है।
आदिम तर्कों के साथ NullPointerException: (Integer) any()
रिटर्न करते समय अशक्त any(Integer.class)
; यह एक कारण हो सकता है NullPointerException
अगर आप int
एक पूर्णांक के बजाय उम्मीद कर रहे हैं । किसी भी स्थिति में, पसंद करें anyInt()
, जो शून्य पर लौटेगा और ऑटो-बॉक्सिंग चरण को भी छोड़ देगा।
NullPointerException या अन्य अपवाद: कॉल when(foo.bar(any())).thenReturn(baz)
वास्तव में कॉल करेंगे foo.bar(null)
, जिसे आपने एक अशक्त तर्क प्राप्त करते समय अपवाद फेंकने के लिए ठूंसा होगा। doReturn(baz).when(foo).bar(any())
ठूंसे हुए व्यवहार को छोड़ देना ।
सामान्य समस्या निवारण
MockitoJUnitRunner का उपयोग करें , या स्पष्ट रूप validateMockitoUsage
से अपने tearDown
या @After
विधि में कॉल करें (जो धावक आपके लिए स्वचालित रूप से करेगा)। यह निर्धारित करने में मदद करेगा कि आपने मिलानकर्ताओं का दुरुपयोग किया है या नहीं।
डिबगिंग उद्देश्यों के लिए, validateMockitoUsage
सीधे अपने कोड में कॉल जोड़ें । यदि आपके पास स्टैक पर कुछ भी है, तो यह फेंक देगा, जो एक बुरे लक्षण की एक अच्छी चेतावनी है।