PHP पारिस्थितिकी तंत्र में कई उपकरण हैं जो सुविधाजनक PHP परीक्षण प्रदान करते हैं। सबसे प्रसिद्ध में से एक
PHPUnit है , जो इस भाषा में परीक्षण के लिए लगभग एक पर्याय है। हालांकि, अच्छे परीक्षण विधियों के बारे में बहुत कुछ नहीं लिखा गया है। परीक्षण क्यों और कब लिखना है, किस तरह के परीक्षण हैं, इत्यादि के लिए कई विकल्प हैं। लेकिन ईमानदार होने के लिए,
यदि आप इसे बाद में नहीं पढ़ सकते हैं, तो परीक्षण लिखने का कोई मतलब नहीं है ।
टेस्ट एक खास तरह का डॉक्यूमेंटेशन है। जैसा कि
मैंने पहले PHP में TDD के बारे में लिखा था , परीक्षण हमेशा (या कम से कम होना चाहिए) स्पष्ट रूप से बात करता है कि किसी विशेष कोड का कार्य क्या है।
यदि एक परीक्षण इस विचार को व्यक्त नहीं कर सकता है, तो परीक्षण खराब है।
मैंने तकनीकों का एक सेट तैयार किया है जो PHP डेवलपर्स को अच्छे, पठनीय और उपयोगी परीक्षण लिखने में मदद करेगा।
आइए बुनियादी बातों से शुरू करें
मानक तकनीकों का एक सेट है जो कई बिना किसी प्रश्न के अनुसरण करता है। मैं उनमें से कई का उल्लेख करूंगा और समझाने की कोशिश करूंगा कि उनकी जरूरत क्यों है।
1. टेस्ट में इनपुट-आउटपुट ऑपरेशन नहीं होना चाहिए
मुख्य कारण : I / O संचालन धीमा और अविश्वसनीय है।
धीमा : भले ही आपके पास दुनिया का सबसे अच्छा हार्डवेयर हो, लेकिन I / O अभी भी मेमोरी एक्सेस की तुलना में धीमा होगा। टेस्ट में हमेशा तेजी से काम करना चाहिए, अन्यथा लोग उन्हें बहुत कम ही चलाएंगे।
अविश्वसनीय : कुछ फाइलें, बायनेरिज़, सॉकेट्स, फ़ोल्डर्स और डीएनएस रिकॉर्ड कुछ मशीनों पर उपलब्ध नहीं हो सकते हैं जिन पर आप परीक्षण कर रहे हैं। जितना अधिक आप I / O के परीक्षण पर भरोसा करते हैं, उतना ही आपके परीक्षण बुनियादी ढांचे से जुड़े होते हैं।
क्या परिचालन I / O से संबंधित हैं:
- फाइलें पढ़ना और लिखना।
- नेटवर्क कॉल।
- बाह्य प्रक्रियाओं को कॉल (
exec
, proc_open
, आदि का उपयोग करके)।
ऐसे हालात हैं जब इनपुट-आउटपुट ऑपरेशन की उपस्थिति आपको परीक्षण तेजी से लिखने की अनुमति देती है। लेकिन सावधान रहें: जांचें कि इस तरह के ऑपरेशन आपके मशीनों पर विकास, विधानसभा और तैनाती के लिए समान काम करते हैं, अन्यथा आपको गंभीर समस्याएं हो सकती हैं।
परीक्षणों को अलग करें ताकि उन्हें I / O संचालन की आवश्यकता न हो: मैंने नीचे एक वास्तुशिल्प समाधान दिया है जो परीक्षणों को इंटरफेस के बीच जिम्मेदारी साझा करके I / O संचालन करने से रोकता है।
एक उदाहरण:
public function getPeople(): array { $rawPeople = file_get_contents( 'people.json' ) ?? '[]'; return json_decode( $rawPeople, true ); }
जब आप इस पद्धति का उपयोग करके परीक्षण शुरू करते हैं, तो एक स्थानीय फ़ाइल बनाई जाएगी, और समय-समय पर स्नैपशॉट बनाए जाएंगे:
public function testGetPeopleReturnsPeopleList(): void { $people = $this->peopleService ->getPeople();
ऐसा करने के लिए, हमें परीक्षण चलाने के लिए आवश्यक शर्तें कॉन्फ़िगर करने की आवश्यकता है। पहली नज़र में, सब कुछ उचित लगता है, लेकिन वास्तव में यह भयानक है।
इस तथ्य के कारण परीक्षण को छोड़ देना कि पूर्वापेक्षाएँ पूरी नहीं हुई हैं, हमारे सॉफ़्टवेयर की गुणवत्ता को सुनिश्चित नहीं करता है। यह केवल कीड़े छिपाएगा!
हम स्थिति को ठीक करते हैं : हम इंटरफ़ेस को जिम्मेदारी शिफ्ट करके I / O संचालन को अलग करते हैं।
अब मुझे पता है कि
JsonFilePeopleProvider
किसी भी मामले में I / O का उपयोग करेगा।
file_get_contents()
बजाय
file_get_contents()
आप
फ्लाईसिस्टम फ़ाइल सिस्टम की तरह एक अमूर्त परत का उपयोग कर सकते हैं, जिसके लिए स्टब्स बनाना आसान है।
और फिर हमें
PeopleService
आवश्यकता क्यों है? अच्छा सवाल है। इसके लिए, परीक्षणों की आवश्यकता है: वास्तुकला को चुनौती देने और बेकार कोड को हटाने के लिए।
2. टेस्ट सचेत और सार्थक होना चाहिए।
मुख्य कारण : परीक्षण प्रलेखन का एक रूप है। उन्हें स्पष्ट, संक्षिप्त और पठनीय रखें।
स्पष्टता और संक्षिप्तता : कोई गड़बड़ नहीं, स्टब्स की कोई हजार लाइनें, बयानों का कोई क्रम नहीं।
पठनीयता : टेस्ट को एक कहानी बतानी चाहिए। "दिया, जब, तब" संरचना इसके लिए उत्कृष्ट है।
एक अच्छे और पठनीय परीक्षण के लक्षण:
- मुखर विधि के लिए केवल आवश्यक कॉल शामिल हैं (अधिमानतः एक)।
- वह बहुत स्पष्ट रूप से बताता है कि दी गई शर्तों के तहत क्या होना चाहिए।
- यह विधि निष्पादन की केवल एक शाखा का परीक्षण करता है।
- वह किसी भी बयान के लिए पूरे ब्रह्मांड के लिए एक ठूंठ नहीं बनाता है।
यह ध्यान रखना महत्वपूर्ण है कि यदि आपके कार्यान्वयन में सशर्त अभिव्यक्ति, संक्रमण ऑपरेटर या लूप शामिल हैं, तो उन्हें सभी परीक्षणों द्वारा स्पष्ट रूप से कवर किया जाना चाहिए। उदाहरण के लिए, ताकि शुरुआती उत्तरों में हमेशा एक परीक्षा हो।
मैं दोहराता हूं: यह कवरेज का नहीं, बल्कि प्रलेखन का विषय है।
यहाँ एक भ्रामक परीक्षा का उदाहरण दिया गया है:
public function testCanFly(): void { $noWings = new Person(0); $this->assertEquals( false, $noWings->canFly() ); $singleWing = new Person(1); $this->assertTrue( !$singleWing->canFly() ); $twoWings = new Person(2); $this->assertTrue( $twoWings->canFly() ); }
आइए "जब, तब दिए गए" प्रारूप को अनुकूलित करें और देखें कि क्या होता है:
public function testCanFly(): void {
"दिए गए" अनुभाग की तरह, "जब" और "तब" को निजी तरीकों में स्थानांतरित किया जा सकता है। यह आपके परीक्षण को अधिक पठनीय बना देगा।
assertEquals
व्यर्थ गड़बड़ है। इसे पढ़ने वाले व्यक्ति को यह समझने के लिए कथन का पता लगाना चाहिए कि इसका क्या मतलब है।
विशिष्ट कथनों का उपयोग करने से आपका परीक्षण बहुत अधिक पठनीय हो जाएगा।
assertTrue()
को एक बूलियन चर प्राप्त करना चाहिए, न कि अभिव्यक्ति की तरह
canFly() !== true
।
पिछले उदाहरण में, हम
false
और
$person->canFly()
बीच
assertEquals
जगह
assertEquals
$person->canFly()
एक साधारण
assertFalse
:
अब सब कुछ बहुत स्पष्ट है! यदि किसी व्यक्ति के पास पंख नहीं हैं, तो उसे उड़ान भरने में सक्षम नहीं होना चाहिए! एक कविता की तरह पढ़ें
अब "आगे के मामले" खंड, जो हमारे पाठ में दो बार दिखाई देता है, एक स्पष्ट संकेत है कि परीक्षण बहुत अधिक बयान करता है।
testCanFly()
विधि पूरी तरह से बेकार है।
आइए फिर से परीक्षा में सुधार करें:
public function testCanFlyIsFalsyWhenPersonHasNoWings(): void { $person = $this->givenAPersonHasNoWings(); $this->assertFalse( $person->canFly() ); } public function testCanFlyIsTruthyWhenPersonHasTwoWings(): void { $person = $this->givenAPersonHasTwoWings(); $this->assertTrue( $person->canFly() ); }
हम परीक्षण विधि का नाम भी बदल सकते हैं ताकि यह वास्तविक परिदृश्य से मेल खाए, उदाहरण के लिए,
testPersonCantFlyWithoutWings
, लेकिन सब कुछ मुझे
testPersonCantFlyWithoutWings
सूट करता
testPersonCantFlyWithoutWings
।
3. परीक्षण अन्य परीक्षणों पर निर्भर नहीं होना चाहिए
मुख्य कारण : परीक्षणों को किसी भी क्रम में सफलतापूर्वक चलना और चलाना चाहिए।
मुझे परीक्षणों के बीच अंतर्संबंध बनाने के लिए पर्याप्त कारण नहीं दिख रहे हैं। हाल ही में मुझे एक लॉगिन फ़ंक्शन टेस्ट करने के लिए कहा गया था, मैं इसे एक अच्छे उदाहरण के रूप में यहां दूंगा।
परीक्षण होना चाहिए:
- लॉग इन करने के लिए JWT टोकन जेनरेट करें।
- लॉगिन फ़ंक्शन निष्पादित करें।
- स्थिति परिवर्तन को मंजूरी दें।
यह इस तरह था:
public function testGenerateJWTToken(): void {
यह कई कारणों से खराब है:
- PHPUnit निष्पादन के इस आदेश की गारंटी नहीं दे सकता है।
- टेस्ट स्वतंत्र रूप से चलाने में सक्षम होना चाहिए।
- समानांतर परीक्षण अनियमित रूप से विफल हो सकते हैं।
इसके आसपास जाने का सबसे आसान तरीका है दिए गए, जब, तब योजना का उपयोग करना। इसलिए परीक्षण अधिक विचारशील होंगे, वे एक कहानी बताएंगे, स्पष्ट रूप से उनकी निर्भरता का प्रदर्शन करते हुए, फ़ंक्शन के परीक्षण के बारे में बताएंगे।
public function testAmazingFeatureChangesState(): void {
हमें प्रमाणीकरण आदि के लिए परीक्षणों को जोड़ने की भी आवश्यकता है, यह संरचना इतनी अच्छी है कि
डिफ़ॉल्ट रूप से Behat का उपयोग किया जाता है ।
4. हमेशा निर्भरता को लागू करें
मुख्य कारण : एक बहुत खराब स्वर - वैश्विक राज्य के लिए एक स्टब बनाने के लिए। निर्भरता के लिए स्टब बनाने में असमर्थता फ़ंक्शन का परीक्षण करने की अनुमति नहीं देती है।
सहायक संकेत:
स्टेटिक स्टेटफुल क्लासेस और सिंगलटन इंस्टेंस के बारे में भूल जाते हैं । यदि आपकी कक्षा किसी चीज़ पर निर्भर करती है, तो इसे बनाइए ताकि इसे लागू किया जा सके।
यहाँ एक दुखद उदाहरण है:
class FeatureToggle { public function isActive( Id $feature ): bool { $cookieName = $feature->getCookieName();
मैं इस शुरुआती उत्तर का परीक्षण कैसे कर सकता हूं?
यह सही है। कोई रास्ता नहीं।
इसका परीक्षण करने के लिए, हमें
Cookies
वर्ग के व्यवहार को समझने की आवश्यकता है और सुनिश्चित करें कि हम इससे जुड़े सभी वातावरण को पुन: उत्पन्न कर सकते हैं, जिसके परिणामस्वरूप कुछ उत्तर मिलेंगे।
यह मत करो।
यदि आप एक निर्भरता के रूप में
Cookies
का एक उदाहरण लागू करते हैं, तो स्थिति को ठीक किया जा सकता है। परीक्षण इस तरह दिखेगा:
एक ही एकल के लिए चला जाता है। इसलिए यदि आप किसी वस्तु को विशिष्ट बनाना चाहते हैं, तो (एंटी) सिंगलटन पैटर्न का उपयोग करने के बजाय अपने निर्भरता इंजेक्टर को सही ढंग से कॉन्फ़िगर करें। अन्यथा, आप ऐसे तरीके लिखेंगे जो केवल
reset()
या
setInstance()
जैसे मामलों के लिए उपयोगी हैं। मेरी राय में, यह पागल है।
परीक्षण को आसान बनाने के लिए वास्तुकला को बदलना पूरी तरह से सामान्य है! और परीक्षण की सुविधा के लिए तरीके बनाना सामान्य नहीं है।
5. प्रोटेक्टेड / प्राइवेट मेथड्स को कभी टेस्ट न करें
मुख्य कारण : वे व्यवहार के हस्ताक्षर का निर्धारण करके हमारे कार्यों के परीक्षण के तरीके को प्रभावित करते हैं: ऐसी स्थिति के तहत, जब मैं ए में प्रवेश करता हूं, तो मैं बी प्राप्त करने की उम्मीद करता हूं।
निजी / संरक्षित तरीके फ़ंक्शन हस्ताक्षर का हिस्सा नहीं हैं ।
मैं निजी तरीकों को "परीक्षण" करने का एक तरीका भी नहीं दिखाना चाहता, लेकिन मैं एक संकेत दूंगा: आप केवल
प्रतिबिंब एपीआई का उपयोग करके ऐसा कर सकते हैं।
निजी तरीकों का परीक्षण करने के लिए प्रतिबिंब का उपयोग करने के बारे में सोचने पर हमेशा किसी तरह खुद को सजा दें! बुरा, बुरा डेवलपर!
परिभाषा के अनुसार, निजी तरीकों को केवल आंतरिक रूप से कहा जाता है। यही है, वे सार्वजनिक रूप से उपलब्ध नहीं हैं। इसका मतलब यह है कि केवल एक ही वर्ग के सार्वजनिक तरीके ऐसे तरीकों को कॉल कर सकते हैं।
यदि आपने अपने सभी सार्वजनिक तरीकों का परीक्षण किया है, तो आपने सभी निजी / संरक्षित तरीकों का भी परीक्षण किया । यदि यह मामला नहीं है, तो स्वतंत्र रूप से निजी / संरक्षित तरीकों को हटा दें, कोई भी उन्हें वैसे भी उपयोग नहीं करता है।
उन्नत युक्तियाँ
मुझे आशा है कि आप अभी तक ऊब नहीं हैं। फिर भी, मुझे बुनियादी बातों के बारे में बात करनी थी। अब मैं स्वच्छ परीक्षण और निर्णय लिखने पर अपनी राय साझा करूंगा जो मेरी विकास प्रक्रिया को प्रभावित करते हैं।
परीक्षण लिखते समय सबसे महत्वपूर्ण बात जो मैं नहीं भूलता:
- अध्ययन।
- त्वरित प्रतिक्रिया।
- दस्तावेजीकरण।
- पुनर्रचना।
- परीक्षण के दौरान डिजाइन।
1. शुरुआत में टेस्ट, अंत नहीं
मान : परीक्षण के दौरान अध्ययन, त्वरित प्रतिक्रिया, प्रलेखन, रीफैक्टरिंग, डिज़ाइन।
यही हर चीज का आधार है। सबसे महत्वपूर्ण पहलू, जिसमें सभी सूचीबद्ध मूल्य शामिल हैं। जब आप पहले से परीक्षण लिखते हैं, तो यह आपको पहले समझने में मदद करता है कि "दिया, कब, तब" योजना को संरचित किया जाना चाहिए। ऐसा करने पर, आप पहले दस्तावेज़, और, अधिक महत्वपूर्ण बात, अपनी आवश्यकताओं को याद रखें और सबसे महत्वपूर्ण पहलुओं के रूप में सेट करें।
क्या कार्यान्वयन से पहले परीक्षण परीक्षण के बारे में सुनना अजीब है? और कल्पना कीजिए कि किसी चीज़ को लागू करना कितना अजीब है, और जब पता लगाने के लिए परीक्षण किया जाता है, तो आपके सभी भाव "जब दिया जाता है, तब" समझ में नहीं आता है।
साथ ही, यह दृष्टिकोण हर दो सेकंड में आपकी उम्मीदों की जाँच करेगा। आपको जल्द से जल्द प्रतिक्रिया मिलती है। कोई फर्क नहीं पड़ता कि सुविधा कितनी बड़ी या छोटी है।
हरित परिक्षण रिफैक्टरिंग के लिए एक आदर्श क्षेत्र है। मुख्य विचार: कोई परीक्षण नहीं - कोई रिफैक्टिंग नहीं। परीक्षण के बिना Refactoring बस खतरनाक है।
अंत में, "जब, तब दिया जाता है" संरचना की स्थापना, यह आपके लिए स्पष्ट हो जाएगा कि आपके तरीकों में क्या अंतर होना चाहिए और उन्हें कैसे व्यवहार करना चाहिए। परीक्षण को साफ रखने से आपको लगातार विभिन्न वास्तु निर्णय लेने के लिए मजबूर होना पड़ेगा। यह आपको कारखानों, इंटरफेस, विरासत में गड़बड़ी, आदि बनाने के लिए मजबूर करेगा और हां, परीक्षण आसान हो जाएगा!
यदि आपके परीक्षण लाइव दस्तावेज़ हैं जो यह समझाते हैं कि आवेदन कैसे काम करता है, तो यह जरूरी है कि वे इसे स्पष्ट करें।
2. खराब परीक्षणों की तुलना में परीक्षणों के बिना बेहतर
मान : अध्ययन, प्रलेखन, रीफैक्टरिंग।
कई डेवलपर्स इस तरह के परीक्षणों के बारे में सोचते हैं: मैं एक विशेषता नहीं लिखूंगा, मैं परीक्षण ढांचे को तब तक चलाऊंगा जब तक कि परीक्षण कुछ नई लाइनों को कवर न कर दें, और उन्हें ऑपरेशन में भेज दें।
यह मुझे लगता है कि आपको उस स्थिति पर अधिक ध्यान देने की आवश्यकता है जब कोई नया डेवलपर इस सुविधा के साथ काम करना शुरू करता है।
परीक्षण इस व्यक्ति को क्या बताएंगे?यदि नाम पर्याप्त रूप से विस्तृत नहीं हैं, तो परीक्षण अक्सर भ्रमित कर रहे हैं। क्या स्पष्ट है:
testCanFly
या
testCanFlyReturnsFalseWhenPersonHasNoWings
?
यदि आपके परीक्षण सिर्फ गन्दे कोड हैं, जो फ्रेमवर्क को अधिक लाइनों को कवर करता है, उदाहरण के लिए जो समझ में नहीं आता है, तो यह रुकने और सोचने का समय है कि क्या इन परीक्षणों को लिखना है।
यहां तक कि इस तरह के बकवास के रूप में
$a
और
$b
चर में निर्दिष्ट करना, या ऐसे नाम निर्दिष्ट करना जो किसी विशिष्ट उपयोग से संबंधित नहीं हैं।
याद रखें : आपके परीक्षण लाइव दस्तावेज़ हैं जो यह समझाने की कोशिश कर रहे हैं कि आपके आवेदन को कैसे व्यवहार करना चाहिए।
assertFalse($a->canFly())
ज्यादा दस्तावेज नहीं
assertFalse($a->canFly())
है। और
assertFalse($personWithNoWings->canFly())
पहले से ही काफी है।
3. टेस्ट को तीव्रता से चलाएं
मान : अध्ययन, त्वरित प्रतिक्रिया, रीफैक्टरिंग।
इससे पहले कि आप सुविधाओं पर काम करना शुरू करें, परीक्षण चलाएं। यदि आप व्यवसाय में उतरने से पहले विफल हो जाते हैं, तो कोड लिखने
से पहले आपको इसके बारे में पता चल जाएगा, और आपको टूटे हुए परीक्षणों को डिबग करने के लिए कीमती मिनट नहीं खर्च करने होंगे, जिनके बारे में आपने भी ध्यान नहीं दिया है।
फ़ाइल को सहेजने के बाद, परीक्षण चलाएं। जितनी जल्दी आप पाते हैं कि कुछ टूट गया है, उतनी ही तेजी से आप इसे ठीक करते हैं और आगे बढ़ते हैं। यदि किसी समस्या को हल करने के लिए वर्कफ़्लो का व्यवधान आपके लिए अनुत्पादक लगता है, तो कल्पना करें कि बाद में आपको समस्या के बारे में पता नहीं होने पर कई कदम पीछे हटना पड़ेगा।
पांच मिनट के लिए सहकर्मियों के साथ चैट करने या गितुब से सूचनाएं देखने के बाद, परीक्षण चलाएं। यदि वे शरमाते हैं, तो आप जानते हैं कि आपने कहाँ छोड़ा था। यदि परीक्षण हरे हैं, तो आप काम करना जारी रख सकते हैं।
किसी भी रिफैक्टरिंग के बाद, यहां तक कि चर नाम भी, परीक्षण चलाते हैं।
गंभीरता से, लानत परीक्षण चलाते हैं। जितनी बार आप सेव का बटन दबाते हैं।
PHPUnit वॉचर आपके लिए यह कर सकता है, और सूचनाएं भी भेज सकता है!
4. बड़े परीक्षण - बड़ी जिम्मेदारी
मान : परीक्षण के दौरान अध्ययन, रीफैक्टरिंग, डिज़ाइन।
आदर्श रूप से, प्रत्येक कक्षा में एक परीक्षण होना चाहिए। इस परीक्षा में इस वर्ग के सभी सार्वजनिक तरीकों के साथ-साथ हर सशर्त अभिव्यक्ति या संक्रमण संचालक को शामिल किया जाना चाहिए ...
आप कुछ इस तरह ले सकते हैं:
- एक वर्ग = एक परीक्षण मामला।
- एक विधि = एक या एक से अधिक परीक्षण।
- एक वैकल्पिक शाखा (यदि / स्विच / कोशिश-पकड़ / अपवाद) = एक परीक्षण।
तो इस सरल कोड के लिए आपको चार परीक्षणों की आवश्यकता होगी:
आपके पास जितने अधिक सार्वजनिक तरीके हैं, उतने अधिक परीक्षणों की आवश्यकता होगी।
कोई भी लंबे दस्तावेज़ पढ़ना पसंद नहीं करता है। चूंकि आपके परीक्षण भी दस्तावेज हैं, इसलिए छोटे आकार और अर्थपूर्णता केवल उनकी गुणवत्ता और उपयोगिता बढ़ाएंगे।
यह भी एक महत्वपूर्ण संकेत है कि आपकी कक्षा जिम्मेदारी संचित कर रही है और यह कई कार्यों को अन्य कक्षाओं में स्थानांतरित करके या सिस्टम को फिर से डिज़ाइन करके इसे फिर से बनाने का समय है।
5. प्रतिगमन समस्याओं को हल करने के लिए परीक्षणों के एक सेट का समर्थन करें
मान : अध्ययन, प्रलेखन, त्वरित प्रतिक्रिया।
फ़ंक्शन पर विचार करें:
function findById(string $id): object { return fromDb((int) $id); }
आपको लगता है कि कोई व्यक्ति "10" संचारित कर रहा है, लेकिन वास्तव में "10 केले" प्रसारित किए जा रहे हैं। यही है, दो मूल्य आते हैं, लेकिन एक शानदार है। आपके पास एक बग है।
आप पहले क्या करेंगे? एक परीक्षण लिखें जो इस तरह के व्यवहार को गलत करेगा!
public function testFindByIdAcceptsOnlyNumericIds(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage( 'Only numeric IDs are allowed.' ); findById("10 bananas"); }
बेशक, परीक्षण कुछ भी संचारित नहीं करते हैं। लेकिन अब आप जानते हैं कि क्या करने की आवश्यकता है ताकि वे संचारित हों। त्रुटि को ठीक करें, परीक्षणों को हरा बनाएं, आवेदन को तैनात करें और खुश रहें।
इस परीक्षा को अपने पास रखो। जब भी संभव हो, प्रतिगमन के साथ समस्याओं को हल करने के लिए डिज़ाइन किए गए परीक्षणों के एक सेट में।
वह सब है! त्वरित प्रतिक्रिया, बग फिक्स, प्रलेखन, प्रतिगमन प्रतिरोधी कोड और खुशी।
अंतिम शब्द
उपर्युक्त में से बहुत कुछ मेरे निजी विचार हैं, जो मेरे करियर के दौरान विकसित हुए हैं। इसका मतलब यह नहीं है कि सलाह सही है या गलत, यह सिर्फ एक राय है।