SavePeople () इकाई परीक्षण किया जाना चाहिए
हाँ, यह चाहिए। लेकिन अपनी परीक्षा की शर्तों को इस तरह से लिखने की कोशिश करें जो कार्यान्वयन से स्वतंत्र हो। उदाहरण के लिए, अपने उपयोग के उदाहरण को एक इकाई परीक्षण में बदलना:
function testSavePeople() {
myDataStore = new Store('some connection string', 'password');
myPeople = ['Joe', 'Maggie', 'John'];
savePeople(myDataStore, myPeople);
assert(myDataStore.containsPerson('Joe'));
assert(myDataStore.containsPerson('Maggie'));
assert(myDataStore.containsPerson('John'));
}
यह परीक्षण कई काम करता है:
- यह फ़ंक्शन के अनुबंध की पुष्टि करता है
savePeople()
- इसे लागू करने की परवाह नहीं है
savePeople()
- इसका उदाहरण उपयोग का दस्तावेज है
savePeople()
ध्यान दें कि आप अभी भी डेटा स्टोर को नकली / ठूंठ / नकली कर सकते हैं। इस मामले में मैं स्पष्ट फ़ंक्शन कॉल के लिए जाँच नहीं करूंगा, लेकिन ऑपरेशन के परिणाम के लिए। इस तरह मेरा परीक्षण भविष्य में होने वाले बदलावों / रिफलेक्टर्स के लिए तैयार है।
उदाहरण के लिए, आपका डेटा स्टोर कार्यान्वयन saveBulkPerson()
भविष्य में एक विधि प्रदान कर सकता है - अब savePeople()
उपयोग के कार्यान्वयन के लिए एक परिवर्तन saveBulkPerson()
यूनिट परीक्षण को तब तक नहीं तोड़ देगा जब तक saveBulkPerson()
कि अपेक्षित रूप से काम करता है। और अगर saveBulkPerson()
किसी तरह उम्मीद के मुताबिक काम नहीं किया जाता है, तो आपकी इकाई परीक्षा इसे पकड़ लेगी ।
या इस तरह के परीक्षण में निर्मित भाषा के निर्माण के परीक्षण के लिए राशि होगी?
जैसा कि कहा गया है, अपेक्षित परिणामों और फ़ंक्शन इंटरफ़ेस के परीक्षण के लिए प्रयास करें, कार्यान्वयन के लिए नहीं (जब तक आप एकीकरण परीक्षण नहीं कर रहे हैं - तब विशिष्ट फ़ंक्शन कॉल को पकड़ना उपयोग का हो सकता है)। यदि फ़ंक्शन को लागू करने के कई तरीके हैं, तो उन सभी को आपकी इकाई परीक्षण के साथ काम करना चाहिए।
आपके प्रश्न के अपडेट के बारे में:
राज्य परिवर्तन के लिए परीक्षण! उदाहरण के लिए, कुछ आटे का उपयोग किया जाएगा। आपके कार्यान्वयन के अनुसार, उपयोग की जाने वाली राशि का उपयोग किया dough
गया है pan
या जोर देता dough
है। pan
फ़ंक्शन कॉल के बाद कुकीज़ को शामिल करें। दावा करें कि oven
पहले की तरह ही खाली / खाली है।
अतिरिक्त परीक्षणों के लिए, किनारे के मामलों की पुष्टि करें: oven
कॉल से पहले खाली न होने पर क्या होता है? यदि पर्याप्त नहीं है तो क्या होगा dough
? यदि pan
पहले से ही भरा हुआ है?
आपको आटा, पैन और ओवन की वस्तुओं से इन परीक्षणों के लिए सभी आवश्यक डेटा को स्वयं करने में सक्षम होना चाहिए। फ़ंक्शन कॉल को कैप्चर करने की आवश्यकता नहीं है। फ़ंक्शन को मानें जैसे कि इसका कार्यान्वयन आपको उपलब्ध नहीं होगा!
वास्तव में, अधिकांश TDD उपयोगकर्ता फ़ंक्शन लिखने से पहले अपने परीक्षण लिखते हैं ताकि वे वास्तविक कार्यान्वयन पर निर्भर न हों।
अपने नवीनतम जोड़ के लिए:
जब कोई उपयोगकर्ता एक नया खाता बनाता है, तो कई चीजों का होना आवश्यक है: 1) डेटाबेस में एक नया उपयोगकर्ता रिकॉर्ड बनाने की आवश्यकता है 2) एक स्वागत योग्य ईमेल भेजने की आवश्यकता है 3) उपयोगकर्ता के आईपी पते को धोखाधड़ी के लिए रिकॉर्ड करने की आवश्यकता है प्रयोजनों।
इसलिए हम एक ऐसा तरीका बनाना चाहते हैं जो सभी "नए उपयोगकर्ता" चरणों को एक साथ जोड़े:
function createNewUser(validatedUserData, emailService, dataStore) {
userId = dataStore.insertUserRecord(validateduserData);
emailService.sendWelcomeEmail(validatedUserData);
dataStore.recordIpAddress(userId, validatedUserData.ip);
}
इस तरह के एक समारोह के लिए मैं / स्टॉक / नकली (जो भी अधिक सामान्य लगता है) dataStore
और emailService
मापदंडों का मजाक उड़ाएगा । यह फ़ंक्शन किसी भी पैरामीटर पर अपने आप में कोई स्टेट ट्रांज़िशन नहीं करता है, यह उन्हें उनमें से कुछ के तरीकों को दर्शाता है। मैं यह सत्यापित करने का प्रयास करूंगा कि फ़ंक्शन को कॉल ने 4 चीजें कीं:
- इसने एक उपयोगकर्ता को डेटा स्टोर में डाला
- इसने एक स्वागतयोग्य ईमेल भेजा (या कम से कम इसी पद्धति को कहा जाता है)
- यह उपयोगकर्ताओं को डेटा स्टोर में IP दर्ज करता है
- इसने किसी भी अपवाद / त्रुटि का प्रतिनिधित्व किया (यदि कोई हो)
पहले 3 चेक को मोक्स, स्टब्स या फेक के साथ किया जा सकता है dataStore
और emailService
(आप वास्तव में परीक्षण करते समय ईमेल नहीं भेजना चाहते हैं)। चूँकि मुझे कुछ टिप्पणियों के लिए इसे देखना था, ये अंतर हैं:
- एक नकली एक वस्तु है जो मूल के समान व्यवहार करती है और कुछ हद तक अप्रभेद्य है। इसका कोड सामान्य रूप से परीक्षणों में पुन: उपयोग किया जा सकता है। यह, उदाहरण के लिए, डेटाबेस आवरण के लिए एक सरल इन-मेमोरी डेटाबेस हो सकता है।
- इस परीक्षण के आवश्यक संचालन को पूरा करने के लिए एक स्टब सिर्फ उतना ही लागू होता है जितना आवश्यक हो। ज्यादातर मामलों में, एक स्टब एक परीक्षण या परीक्षणों के एक समूह के लिए विशिष्ट होता है, जिसमें मूल के तरीकों के केवल एक छोटे सेट की आवश्यकता होती है। इस उदाहरण में, यह एक हो सकता है
dataStore
कि सिर्फ एक उपयुक्त संस्करण लागू करता है insertUserRecord()
और recordIpAddress()
।
- एक मॉक एक ऐसी वस्तु है जो आपको यह सत्यापित करने की सुविधा देती है कि इसका उपयोग कैसे किया जाता है (सबसे अधिक बार आपको इसके तरीकों के लिए कॉल का मूल्यांकन करने से)। मैं उन्हें इकाई परीक्षणों में संयम से इस्तेमाल करने की कोशिश करता हूं क्योंकि उनका उपयोग करके आप वास्तव में फ़ंक्शन कार्यान्वयन का परीक्षण करने की कोशिश करते हैं और इसके इंटरफ़ेस का पालन नहीं करते हैं, लेकिन उनके पास अभी भी उनके उपयोग हैं। कई मॉक फ्रेमवर्क आपकी मदद करने के लिए मौजूद हैं, जिनकी आपको जरूरत है।
ध्यान दें कि यदि इन विधियों में से कोई भी एक त्रुटि फेंकता है, तो हम चाहते हैं कि त्रुटि कॉलिंग कोड तक बुलबुले के रूप में हो, ताकि यह त्रुटि को संभाल सके क्योंकि यह फिट दिखता है। यदि इसे एपीआई कोड द्वारा बुलाया जा रहा है, तो यह त्रुटि को एक उपयुक्त HTTP प्रतिक्रिया कोड में बदल सकता है। यदि इसे वेब इंटरफ़ेस द्वारा बुलाया जा रहा है, तो यह उपयोगकर्ता को प्रदर्शित होने के लिए एक उपयुक्त संदेश में त्रुटि का अनुवाद कर सकता है, और इसी तरह। मुद्दा यह है कि फ़ंक्शन को यह पता नहीं है कि त्रुटियों को कैसे संभालना है।
अपेक्षित अपवाद / त्रुटियां वैध परीक्षण मामले हैं: आप पुष्टि करते हैं कि, यदि ऐसी कोई घटना होती है, तो फ़ंक्शन उस तरीके का व्यवहार करता है जिस तरह से आप अपेक्षा करते हैं। यह वांछित होने पर संबंधित नकली / नकली / ठूंठ वस्तु को फेंकने से प्राप्त किया जा सकता है।
मेरे भ्रम का सार यह है कि इस तरह के फ़ंक्शन को इकाई परीक्षण के लिए परीक्षण में सटीक कार्यान्वयन को दोहराने के लिए आवश्यक लगता है (यह निर्दिष्ट करके कि विधियों को एक निश्चित क्रम में मोक्स पर कहा जाता है) और यह गलत लगता है।
कभी-कभी यह करना पड़ता है (हालांकि आप ज्यादातर एकीकरण परीक्षणों में इस बारे में परवाह करते हैं)। अधिक बार, अपेक्षित साइड इफेक्ट्स / राज्य परिवर्तनों को सत्यापित करने के अन्य तरीके हैं।
सटीक कार्य कॉल को सत्यापित करने के बजाय भंगुर इकाई परीक्षणों के लिए बनाता है: मूल फ़ंक्शन में केवल छोटे परिवर्तन उन्हें विफल करने का कारण बनता है। यह वांछित हो सकता है या नहीं, लेकिन जब भी आप किसी फ़ंक्शन को बदलते हैं, तो इसी यूनिट टेस्ट (एस) में बदलाव की आवश्यकता होती है (जैसा कि यह रीफैक्टरिंग, अनुकूलन, बग फिक्सिंग, ...)।
अफसोस की बात है कि उस मामले में इकाई परीक्षण अपनी कुछ विश्वसनीयता खो देता है: चूंकि इसे बदल दिया गया था, यह परिवर्तन की पुष्टि नहीं करता है क्योंकि परिवर्तन पहले की तरह ही व्यवहार करता है।
एक उदाहरण के लिए, oven.preheat()
अपने कुकी बेकिंग उदाहरण में किसी को कॉल (अनुकूलन!) जोड़ने पर विचार करें :
- यदि आप ओवन ऑब्जेक्ट का मजाक उड़ाते हैं, तो यह उम्मीद नहीं करेगा कि कॉल और परीक्षण विफल हो जाएगा, हालांकि विधि का अवलोकन व्यवहार नहीं बदला (आपके पास अभी भी कुकीज़ का एक पैन है, उम्मीद है)।
- एक स्टब विफल हो सकता है या नहीं हो सकता है, इस पर निर्भर करता है कि आपने केवल परीक्षण करने के तरीके जोड़े हैं या कुछ डमी विधियों के साथ पूरे इंटरफ़ेस।
- एक नकली विफल नहीं होना चाहिए, क्योंकि यह विधि (इंटरफ़ेस के अनुसार) को लागू करना चाहिए
मेरी इकाई परीक्षणों में, मैं यथासंभव सामान्य रहने की कोशिश करता हूं: यदि कार्यान्वयन में बदलाव होता है, लेकिन दृश्यमान व्यवहार (कॉलर के दृष्टिकोण से) अभी भी समान है, मेरे परीक्षण पास होने चाहिए। आदर्श रूप से, मौजूदा इकाई परीक्षण को बदलने के लिए मुझे एकमात्र मामला बग फिक्स (परीक्षण के तहत कार्य नहीं, परीक्षण) होना चाहिए।