आपने एक नई परियोजना शुरू की है और यह आपके कोड के लिए किसी तृतीय-पक्ष सेवा पर निर्भर होने का समय है। यह ElasticSearch, Resque, एक बिलिंग प्रदाता, या केवल एक मनमाना HTTP API जैसा कुछ हो सकता है। आप एक अच्छे डेवलपर हैं, इसलिए आप चाहते हैं कि इस कोड का अच्छी तरह से परीक्षण किया जाए। लेकिन आप उस कोड का परीक्षण कैसे करते हैं जो एक ऐसी सेवा के लिए अनुरोध करता है जो पूरी तरह से आपके नियंत्रण से बाहर है?
आप परीक्षणों को छोड़ सकते हैं, लेकिन आप जल्द ही अस्थिर नींव पर अधिक कोड जमा करेंगे। परीक्षण नहीं किया गया कोड अधिक जटिल कोड को आकर्षित करता है, और आप अंततः महसूस करेंगे कि कोड रिफैक्टर के लिए बहुत खतरनाक है क्योंकि आपके पास सुरक्षित महसूस करने के लिए आवश्यक परीक्षण कवरेज नहीं है। आप अपने भविष्य के काम के लिए एक स्थिर नींव बनाना चाहते हैं, लेकिन इसके बजाय आप एक अचूक गड़बड़ी के साथ समाप्त हो गए हैं।
इस स्थिति से बचना जितना लगता है उससे कहीं अधिक आसान है! कुछ टूल और थोड़े से अपफ्रंट प्रयास के साथ, आप अपने परीक्षणों को उन सेवाओं से अलग कर सकते हैं जिन पर आपका कोड निर्भर करता है, सरल कोड लिख सकता है, और आपके द्वारा लिखे गए कोड को बेहतर बनाने का आत्मविश्वास रखता है-बिना बग पेश किए। विलंब करने के बजाय क्योंकि आप नहीं जानते कि उन अगले परीक्षणों को कैसे लिखना है, आप अपने कोड और बाहरी दुनिया के बीच की बातचीत को देख सकते हैं, और यह जान सकते हैं कि इसके बीच में कैसे कूदना है।
मोचा:द क्विक-एंड-डर्टी अप्रोच
मोचा आपके कोड और बाहरी दुनिया के बीच में आने का सबसे आसान तरीका है।
उदाहरण के तौर पर, मान लें कि आपके पास Cart
है ऑब्जेक्ट जो चेक आउट होने पर क्रेडिट कार्ड चार्ज को ट्रिगर करता है। आप यह सुनिश्चित करना चाहते हैं कि चार्ज विफल होने पर कार्ट में एक त्रुटि संदेश संलग्न है।
आप शायद नहीं चाहेंगे कि आपके परीक्षण वास्तव में हिट . हों हर बार परीक्षण चलने पर बिलिंग सिस्टम। यहां तक कि अगर आपने किया, तो उस सेवा को विफलता वापस करने के लिए मजबूर करना मुश्किल हो सकता है। मोचा के साथ यह कैसा दिखेगा:
def test_error_message_set_on_charge_failure
cart = Cart.new(items)
cart.stubs(:charge!).returns(false) # mocha in action
cart.checkout!
assert_equal "The credit card could not be charged", cart.credit_card_error
end
मोचा आपके परीक्षणों को विफल भी कर सकता है यदि विधियों को आपकी अपेक्षा के अनुरूप नहीं कहा जाता है:
def test_only_bill_once_per_cart
cart = Cart.new(items)
cart.expects(:charge!).once # Don't double-bill, no matter how many times we check out
cart.checkout!
cart.checkout!
end
मोचा का उपयोग करना आसान है, लेकिन अविश्वसनीय रूप से आसान हो सकता है। आपको सावधान रहना होगा कि आप केवल का मज़ाक उड़ा रहे हैं वह व्यवहार जो आप नहीं करना चाहते हैं - बहुत अधिक उपहास करना और वास्तविक बग छिपाना आसान है। आप इस दृष्टिकोण के साथ ओवरबोर्ड नहीं जाना चाहते:expects
. से भरे परीक्षण और stubs
पढ़ना और सोचना मुश्किल है।
नकली परीक्षण:मेरा पसंदीदा तरीका
यदि आप हर समय एक ही वस्तु पर एक ही तरीके का उपहास या ठूंठ लगाते हैं, तो आप अपने मॉक को पूर्ण वस्तुओं (कभी-कभी परीक्षण नकली कहा जाता है) के लिए प्रचारित कर सकते हैं। ), इस तरह:
def test_billed_full_amount_minus_discount
test_payment_provider = TestPaymentProvider.new # A fake payment provider
cart = Cart.new(items, discount: 30, provider: test_payment_provider)
cart.checkout!
assert_equal items.sum(:&price) * 0.7, test_payment_provider.total_charges
end
नकली महान हैं:
-
आपका नकली अपनी आंतरिक स्थिति पर नज़र रख सकता है
नकली में कस्टम अभिकथन संदेश और सहायक कार्य हो सकते हैं जो आपके परीक्षणों को लिखना आसान बनाते हैं, जैसे
total_charges
विधिउपरोक्त उदाहरण में। -
एक पूर्ण वस्तु के रूप में, आपको अतिरिक्त संपादक और भाषा समर्थन मिलता है
यदि आप एक संपादक का उपयोग कर रहे हैं जो इसका समर्थन करता है, तो आप मोचा के साथ अलग-अलग तरीकों को रोककर स्वत:पूर्ण, इनलाइन दस्तावेज़ीकरण और अन्य चीजें प्राप्त कर सकते हैं जो आपको नहीं मिलती हैं। आपको बेहतर सत्यापन, अपवाद प्रबंधन, और जो कुछ भी आप अपने नकली में बनाना चाहते हैं, वह भी मिलेगा।
-
यदि आप विकास मोड में नकली का उपयोग करते हैं, तो आपके पास वास्तविक सेवा से कोई संबंध नहीं होना चाहिए
आप बस में अपना ऐप लिख सकते हैं, आपके पास अपने लैपटॉप की बैटरी खत्म होने वाली सेवाओं का जंगल नहीं होना चाहिए, और आप इन नकली सेवाओं को सेट कर सकते हैं ताकि आपको बहुत अधिक की आवश्यकता के बिना किनारे के मामलों के माध्यम से काम करने के लिए आवश्यक डेटा वापस मिल सके। सेटअप।
-
इन वस्तुओं का उपयोग आपके परीक्षणों के बाहर किया जा सकता है
यह शायद फेक का मेरा पसंदीदा हिस्सा है। आपके पास एक तृतीय पक्ष सेवा और आपकी नकली, इन-मेमोरी सरणी दोनों के लिए लॉगिंग क्लाइंट लॉग हो सकता है। तब आप इस सरणी की सामग्री को अपनी साइट के व्यवस्थापक दृश्य में डंप कर सकते हैं , यह सत्यापित करना बहुत आसान बनाता है कि आप वही लॉग कर रहे हैं जो आपको लगता है कि आप लॉगिंग कर रहे हैं।
आप ऐसा कुछ कर सकते हैं:
fake_backend = FakeBackend.new
LoggingService.backends = [RealBackend.new, fake_backend]
LoggingService.debug("TEST MESSAGE PLEASE IGNORE")
fake_backend.messages.first # => [:debug, "TEST MESSAGE PLEASE IGNORE"]
एक नकली लिखना अलग-अलग तरीकों को खत्म करने की तुलना में अधिक प्रयास करता है, लेकिन अभ्यास के साथ एक सहायक नकली बनाने में एक या दो घंटे से अधिक समय नहीं लगना चाहिए। यदि आप एक ऐसा निर्माण करते हैं जो अन्य लोगों के लिए उपयोगी हो, तो इसे साझा करें! मैंने बहुत समय पहले एक अनुरेखण इकाई का निर्माण किया था, और आज भी बहुत से लोग इसका उपयोग करते हैं।
मैं इन वस्तुओं को किसी भी तरह से कैसे इंजेक्ट कर सकता हूं?
इन फेक से किसी तरह बात करने के लिए आपको अपनी वस्तुओं का परीक्षण करना होगा। सौभाग्य से, रूबी का दुरुपयोग करना इतना आसान है कि नकली इंजेक्शन लगाना आमतौर पर कठिन नहीं होता है।
यदि आप परीक्षण के तहत वस्तु के एपीआई को नियंत्रित करते हैं, तो एक डिफ़ॉल्ट पैरामीटर, एक विशेषता, या एक कंस्ट्रक्टर विकल्प जोड़ना सबसे अच्छा है जहां आप अपना नकली सेट कर सकते हैं:
class Card
attr_reader :provider
def initialize(items, options={})
@provider = options.fetch(:provider) { RealProvider.new }
end
end
जब आप वास्तविक सेवा से बात कर रहे होते हैं तो यह साफ होता है और आपको बाद में लचीलापन जोड़ने के लिए एक हुक देता है।
यदि आप ऑब्जेक्ट को नियंत्रित नहीं करते हैं या अतिरिक्त पैरामीटर नहीं जोड़ना चाहते हैं, तो आप हमेशा बंदर पैच कर सकते हैं:
# if in test mode
Card.class_eval do
def provider
@provider ||= TestProvider.new
end
end
यह परीक्षण में अधिक बदसूरत है, लेकिन ऐसे वातावरण में क्लीनर है जो नकली का उपयोग नहीं करते हैं।
अभी अपना नकली बनाना शुरू करें
अभ्यास के साथ नकली बनाना आसान हो जाता है, इसलिए आपको इसे अभी आज़माना चाहिए:
- एक ऐसा परीक्षण ढूंढें जो किसी बाहरी सेवा से बात करता हो। यदि आप इंटरनेट से डिस्कनेक्ट कर देते हैं तो परीक्षण विफल हो जाएंगे, अच्छे उम्मीदवार हैं।
- पता लगाएं कि वास्तव में कौन सी वस्तु संचार करती है, और आपका कोड उस वस्तु को क्या कॉल करता है।
- उस ऑब्जेक्ट की कक्षा का अधिकतर खाली डुप्लिकेट बनाएं, और यह आपके द्वारा एक सरणी में किए गए कॉल को लॉग करें।
- की गई कॉलों की सूची वापस करने के लिए अपने नकली में एक विधि जोड़ें।
- अपनी नई नकली वस्तु के साथ वास्तविक वस्तु की अदला-बदली करें, और आपके कोड द्वारा की जाने वाली कॉलों के विरुद्ध कुछ अभिकथन लिखें।
अगर आप इसे आजमाते हैं, तो मुझे बताएं कि यह कैसा चल रहा है!
इन तकनीकों के साथ, यह तब तक लंबा नहीं होगा जब तक आप अपने आवेदन और बाहरी दुनिया के बीच सबसे अजीब बातचीत को वश में करने में सक्षम नहीं होंगे। सही जगह पर एक साधारण स्टब आपको आत्मविश्वास के साथ अपना अच्छी तरह से परीक्षित कोड भेजने देगा।