Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Ruby

RSpec मॉक्स में महारत: एक व्यापक चरण-दर-चरण गाइड

RSpec में मॉक क्या है?

(या सामान्य रूप से मॉक, क्योंकि यह अवधारणा RSpec के लिए अद्वितीय नहीं है।)

मॉक टेस्टिंग के लिए उपयोग किया जाने वाला एक ऑब्जेक्ट है।

आप दो ऑब्जेक्ट्स के बीच इंटरैक्शन का परीक्षण करने के लिए मॉक्स का उपयोग करते हैं। नियमित अपेक्षा की तरह आउटपुट मान का परीक्षण करने के बजाय।

उदाहरण के लिए:

आप एक API लिख रहे हैं जो इमेजेज को फ्लिप करता है।

अपना खुद का इमेज-मैनिपुलेशन कोड लिखने के बजाय आप mini_magick जैसे जेम का उपयोग करते हैं।

आप अपने कोड और इस बाहरी निर्भरता के बीच इंटरैक्शन का परीक्षण करना चाहते हैं... इसलिए आप एक मॉक लिखते हैं जो ImageProcessor क्लास पर सही मेथड्स के कॉल होने की अपेक्षा करता है।

इसका मतलब है कि आप हर बार अपने टेस्ट चलाने पर इमेजेज फ्लिप नहीं करेंगे (एक धीमा ऑपरेशन)।

यह कैसे काम करता है?

मॉक्स मूल ऑब्जेक्ट को प्रतिस्थापित करते हैं, इसलिए वास्तविक मेथड्स नहीं कॉल किए जाएंगे।

कुछ कोड उदाहरणों का समय!

RSpec मॉक उदाहरण

यहां ImageFlipper टेस्ट है:

 RSpec.describe "ImageFlipper" do it "calls the flip method with the correct arguments" do mock = double("mini_magick") expect(mock).to receive(:flip).with("ruby.jpg") img = ImageFlipper.new(mock) img.flip("ruby.jpg") end end 

इस टेस्ट के साथ हम TDD का उपयोग करके अपना कोड लिख सकते हैं।

पहले:

हमें एक ImageFlipper क्लास लिखने की आवश्यकता है।

इस तरह:

 class ImageFlipper def initialize(image_processor) @image_processor = image_processor end end 

हमें एक flip मेथड भी चाहिए:

 def flip(file_name) end 

अब हमें RSpec से यह प्रतिक्रिया मिलती है:

 Failures: 1) ImageFlipper calls the flip method with the correct arguments Failure/Error: expect(mock).to receive(:flip).with("ruby.jpg") (Double "mini_magick").flip("ruby.jpg") expected: 1 time with arguments: ("ruby.jpg") received: 0 times # ./rspec-mocks.rb:6:in `block (2 levels) in <top (required)>' 

यह कह रहा है कि flip मेथड को 0 बार कॉल किया गया था, लेकिन इसकी अपेक्षा 1 बार थी।

आप इसे वह देकर टेस्ट पास कर सकते हैं जो यह चाहता है:

 def flip(file_name) @image_processor.flip(file_name) end 

और वहां आपके पास है, हमारे पास एक पासिंग टेस्ट है:

 . Finished in 0.00751 seconds (files took 0.11157 seconds to load) 1 example, 0 failures 

आइए समीक्षा करें: हमने यहां क्या किया?

हमने एक ImageFlipper क्लास बनाई जो एक image_processor लेती है।

यह प्रोसेसर flip मेथड का जवाब देता है।

हम यह टेस्ट करने के लिए मॉक का उपयोग करते हैं कि क्या इस मेथड को एक बार, एक आर्गुमेंट के साथ कॉल किया गया था।

मुझे पता है।

यह उदाहरण सरल है।

लेकिन आप ImageFlipper के पूर्ण कार्यान्वयन की कल्पना कर सकते हैं जो जांचता है कि फाइल मौजूद है, यह एक वैध इमेज है, आदि।

मॉक और वैल्यू टेस्टिंग के बीच अंतर

एक नियमित टेस्ट में आप मेथड के रिटर्न मान की जांच करते हैं:

"क्या इस मेथड ने एक फ्लिप की हुई इमेज वापस की?"

मॉक का उपयोग करते समय आप व्यवहार का परीक्षण कर रहे हैं:

"क्या हमने दूसरों को सही काम करने के लिए कहा, सही जानकारी के साथ, और ठीक उतनी बार जितनी हमें जरूरत है?"

मॉक्स बनाम स्टब्स

एक और भ्रम बिंदु मॉक्स और स्टब्स की तुलना के बारे में है।

अंतर क्या है?

  • स्टब केवल एक पूर्वनिर्धारित प्रतिक्रिया वाला मेथड है, यह व्यवहार की परवाह नहीं करता।
  • मॉक मेथड्स के कॉल होने की अपेक्षा करता है, यदि वे कॉल नहीं किए जाते तो टेस्ट फेल हो जाएगा।

यहां RSpec में एक स्टब है:

 stub = double("json") allow(stub).to receive(:response) do {"blog"=>"rubyguides.com", "rating"=>"5/5"}.to_json end 

allow मेथड इसे स्टब बनाता है।

हम अपने टेस्ट ऑब्जेक्ट double("json") को इस मेथड को प्राप्त करने और प्रतिक्रिया देने की अनुमति दे रहे हैं, लेकिन हम यह जांच नहीं कर रहे हैं कि इसे कॉल किया जा रहा है।

यही अंतर है!

सत्यापित डबल्स का उपयोग कैसे करें

मॉक्स और स्टब्स के नुकसानों में से एक यह है कि आप अपने प्रोडक्शन कोड में मौजूद नहीं मेथड का उपयोग कर सकते हैं।

क्योंकि मेथड का नाम बदल गया है... या शायद आपने टाइपो कर दिया!

मिलिए सत्यापित डबल्स से।

एक सत्यापित डबल का उपयोग या तो स्टब (allow) या मॉक (expect) के रूप में किया जा सकता है और यह जांच करेगा कि इस नाम का कोई मेथड मौजूद है।

उदाहरण:

 mock = instance_double(ImageProcessor) 

यदि मेथड मौजूद नहीं है तो यह एक त्रुटि उठाएगा:

 1) ImageFlipper calls the flip method with the correct arguments Failure/Error: expect(mock).to receive(:flip).with("ruby.jpg") the ImageProcessor class does not implement the instance method: flip 

लेकिन यह सही ढंग से काम करेगा यदि मेथड मौजूद है।

मॉक्स मान वापस करना

आइए मॉकिंग पर वापस चलते हैं।

पिछले उदाहरण में हमारे पास यह था:

 expect(mock).to receive(:flip).with("ruby.jpg") 

जब आपका कोड flip कॉल करता है, तो मॉक nil वापस करेगा।

यदि कोड nil के अलावा कुछ मान की अपेक्षा कर रहा है तो इसके परिणामस्वरूप त्रुटि होगी।

आप मॉक को परिणाम वापस करके इसे ठीक कर सकते हैं।

इस तरह:

 expect(mock).to receive(:flip).with("ruby.jpg").and_return("ruby-flipped.jpg") 

इंस्टेंस मेथड्स को मॉक कैसे करें

मान लीजिए कि आपके पास ऐसा कोड है:

 class NumberGenerator def random "A" * rand(1..10) end end 

इस मेथड का परीक्षण करना मुश्किल है क्योंकि रैंडमनेस के कारण।

RSpec आपको rand को मॉक या स्टब करने की अनुमति देता है।

इस तरह:

 it "generates a random number" do generator = NumberGenerator.new allow(generator).to receive(:rand).and_return(5) expect(generator.random).to eq("AAAAA") end 

अब:

rand एक निश्चित मान लौटाता है ताकि आप इसका उपयोग अपने मेथड के परिणाम का परीक्षण करने के लिए कर सकें।

आदर्श रूप से, आप अपनी निर्भरता को इंजेक्ट करना चाहेंगे (इस मामले में rand फ़ंक्शन) ताकि आप इसे नियंत्रित कर सकें। निर्भरता इंजेक्ट करने का मतलब है कि आप इसे पैरामीटर के रूप में पास करते हैं, कुछ फैंसी नहीं।

लेकिन कभी-कभी मेथड को स्टब करना अधिक सुविधाजनक होता है।

मॉक्स का उपयोग कब करें?

अब बड़े सवाल के लिए...

वास्तव में आपको मॉक्स का उपयोग कब करना चाहिए?

सॉफ्टवेयर विकास एक जटिल विषय है।

लेकिन कुछ दिशानिर्देश हैं जिनका आप पालन कर सकते हैं:

  1. यदि टेस्ट के तहत मेथड एक मान लौटाता है और इसका कोई साइड इफेक्ट नहीं है (फाइल बनाना, API रिक्वेस्ट करना, आदि) तो आपको मॉक की आवश्यकता नहीं है। बस रिटर्न मान की जांच करें।
  2. यदि मेथड बाहरी ऑब्जेक्ट्स के साथ काम कर रहा है और उन्हें ऑर्डर भेज रहा है, तो आप इन ऑब्जेक्ट्स के साथ इंटरैक्शन को मॉक कर सकते हैं।
  3. यदि मेथड किसी बाहरी सेवा से डेटा का अनुरोध कर रहा है (जैसे API), तो आप टेस्टिंग उद्देश्यों के लिए इस डेटा को प्रदान करने के लिए स्टब का उपयोग कर सकते हैं।

आप बाहरी दुनिया के साथ इंटरैक्शन के लिए मॉकिंग को आरक्षित करना चाहते हैं।

दूसरे शब्दों में...

अपने स्वयं के एप्लिकेशन की क्लासेज को मॉक करने से बचें!

क्यों?

क्योंकि यह आपके टेस्ट्स को कार्यान्वयन विवरणों के साथ जोड़ता है और आपके कोड को बदलना कठिन बना देता है।

एकमात्र अपवाद उन क्लासेज के लिए है जो थर्ड-पार्टी कोड के लिए रैपर हैं।

अधिक जानने के लिए यह वीडियो देखें:

सारांश

आपने RSpec मॉक्स, स्टब्स और सत्यापित डबल्स के बारे में सीखा!

कृपया इस लेख को साझा करें ताकि अधिक लोग इसका आनंद ले सकें और इससे लाभ उठा सकें।

पढ़ने के लिए धन्यवाद 🙂


  1. Ruby के grep मेथड में महारत: कोड उदाहरणों के साथ एक व्यावहारिक गाइड Ruby के grep मेथड में महारत: कोड उदाहरणों के साथ एक व्यावहारिक गाइड

    आइए grep मेथड के बारे में बात करते हैं। यह मेथड आपके लिए क्या कर सकता है? आप enumerable ऑब्जेक्ट्स को फ़िल्टर करने के लिए Grep का उपयोग कर सकते हैं, जैसे Arrays और Ranges। "लेकिन select पहले से ही ऐसा करता है!" हाँ, लेकिन grep अलग तरीके से काम करता है और अलग परिणाम उत्पन्न करता है। आइए कुछ

  1. Ruby के Map मेथड में महारत: उदाहरणों के साथ एक व्यावहारिक गाइड Ruby के Map मेथड में महारत: उदाहरणों के साथ एक व्यावहारिक गाइड

    Map एक Ruby मेथड है जिसका उपयोग आप Arrays, Hashes और Ranges के साथ कर सकते हैं। map का मुख्य उपयोग डेटा को ट्रांसफॉर्म करना है। उदाहरण के लिए: स्ट्रिंग्स की एक सरणी दिए जाने पर, आप हर स्ट्रिंग पर जा सकते हैं और हर कैरेक्टर को UPPERCASE बना सकते हैं। या यदि आपके पास User ऑब्जेक्ट्स की एक सूची है... आ

  1. रूबी थ्रेड्स में महारत: मल्टीथ्रेडिंग के लिए एक शुरुआती-अनुकूल गाइड रूबी थ्रेड्स में महारत: मल्टीथ्रेडिंग के लिए एक शुरुआती-अनुकूल गाइड

    रूबी में थ्रेड क्या है? थ्रेड्स आपके रूबी प्रोग्राम्स को एक ही समय में कई चीजें करने देते हैं। जैसी चीजें: एकाधिक फाइलें पढ़ना एकाधिक वेब अनुरोधों को संभालना एकाधिक API कनेक्शन बनाना थ्रेड्स का उपयोग करने के परिणामस्वरूप, आपके पास एक मल्टी-थ्रेडेड रूबी प्रोग्राम होगा, जो चीजों को तेजी से पूरा करने