जब यूनिट टेस्ट झूठ बोलते हैं और बग बने रहते हैं
\n\nआपने 20 यूनिट टेस्ट लिखे। सभी हरे हैं। CI पास हो जाता है। आप संतुष्ट हैं। और फिर - प्रोडक्शन में एक बग। परिचित लगता है? क्लासिक परिदृश्य: आपने केवल उन्हीं मामलों का परीक्षण किया जो आपने स्वयं सोचे थे। और वास्तविकता, जैसे कि जानबूझकर, ऐसे संयोजन देती है जिनके बारे में आपने सोचा भी नहीं था।
\n\nGo में एक शक्तिशाली लेकिन कम सराहा गया दृष्टिकोण है - प्रॉपर्टी-आधारित परीक्षण (या गुणों का परीक्षण)। विशिष्ट इनपुट और आउटपुट की जाँच करने के बजाय, आप उन गुणों का वर्णन करते हैं जिन्हें फ़ंक्शन को संतुष्ट करना चाहिए, और फ्रेमवर्क स्वयं सैकड़ों यादृच्छिक परीक्षण डेटा उत्पन्न करता है। यदि कोई गुण भंग होता है - तो आपको एक बग मिल गया है।
\n\nइस लेख में, हम gopter लाइब्रेरी की मदद से Go में प्रॉपर्टी-आधारित परीक्षण को लागू करने का तरीका समझेंगे, वास्तविक उदाहरण लिखेंगे और देखेंगे कि कौन से बग पकड़े जा सकते हैं। चलिए शुरू करते हैं!
प्रॉपर्टी-आधारित परीक्षण क्या है और इसकी आवश्यकता क्यों है?
\n\nकल्पना करें कि आप एक सॉर्टिंग फ़ंक्शन का परीक्षण कर रहे हैं। सामान्य यूनिट टेस्ट:
\n\nfunc TestSort(t *testing.T) {\n input := []int{3, 1, 2}\n result := sort(input)\n expected := []int{1, 2, 3}\n if !reflect.DeepEqual(result, expected) {\n t.Errorf("got %v, want %v", result, expected)\n }\n}\n\nठीक है, यह काम करता है। लेकिन क्या होगा अगर ऐरे खाली है? क्या होगा अगर सभी तत्व समान हैं? क्या होगा अगर ऋणात्मक संख्याएँ हैं? आप 10 और टेस्ट लिख सकते हैं, लेकिन फिर भी कुछ छूट जाएगा।
\n\nप्रॉपर्टी-आधारित परीक्षण इस समस्या को मौलिक रूप से हल करता है: आप इनवेरिएंट तैयार करते हैं - वे गुण जो किसी भी सही इनपुट के लिए सत्य होने चाहिए। उदाहरण के लिए, सॉर्टिंग के लिए:
\n\n- \n
- सॉर्ट किए गए ऐरे की लंबाई मूल ऐरे की लंबाई के बराबर होती है। \n
- मूल ऐरे का प्रत्येक तत्व सॉर्ट किए गए ऐरे में मौजूद होता है (और इसके विपरीत)। \n
- ऐरे आरोही क्रम में सॉर्ट किया गया है। \n
फ्रेमवर्क (उदाहरण के लिए, gopter या बिल्ट-इन testing/quick) यादृच्छिक इनपुट डेटा उत्पन्न करता है और जाँचता है कि सभी गुण पूरे होते हैं। यदि कोई बग है - तो आपको इसके बारे में पता चल जाएगा, भले ही आपको पता न हो कि कहाँ देखना है।
प्रॉपर्टी-आधारित परीक्षण के लिए Go लाइब्रेरीज़
\n\nGo इकोसिस्टम में कई उपकरण हैं:
\n\n- \n
testing/quick- बिल्ट-इन पैकेज, न्यूनतम, लेकिन सीमित क्षमताओं के साथ। \n gopter- जनरेटर, श्रिंकिंग (इनपुट डेटा को छोटा करना) और लचीली सेटिंग्स के साथ एक शक्तिशाली लाइब्रेरी। हम इसी की सलाह देते हैं। \n rapid- एक आधुनिक विकल्प, अधिक प्रदर्शनकारी। \n
हम gopter का उपयोग करेंगे, क्योंकि इसके पास बेहतर दस्तावेज़ीकरण और समुदाय है। स्थापना:
go get github.com/leanovate/gopter\n\nGo में पहला प्रॉपर्टी-आधारित टेस्ट लिखना
\n\nमान लीजिए, हमारे पास एक फ़ंक्शन Reverse है जो स्ट्रिंग को उलटता है:
func Reverse(s string) string {\n runes := []rune(s)\n for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {\n runes[i], runes[j] = runes[j], runes[i]\n }\n return string(runes)\n}\n\nकिस गुण की जाँच की जा सकती है? यदि स्ट्रिंग को दो बार उलटा जाए, तो हमें मूल स्ट्रिंग मिलनी चाहिए:
\n\nimport (\n "testing"\n "github.com/leanovate/gopter"\n "github.com/leanovate/gopter/gen"\n)\n\nfunc TestReverseTwice(t *testing.T) {\n properties := gopter.NewProperties(nil)\n\n properties.Property("reverse(reverse(s)) == s", prop.ForAll(\n func(s string) bool {\n return Reverse(Reverse(s)) == s\n },\n gen.AnyString(),\n ))\n\n properties.TestingRun(t)\n}\n\nटेस्ट चलाएँ - और gopter 100 यादृच्छिक स्ट्रिंग उत्पन्न करेगा, गुण की जाँच करेगा। यदि सब कुछ ठीक है - टेस्ट हरा है। यदि नहीं - तो आपको एक काउंटरएग्ज़ाम्पल (सबसे छोटी स्ट्रिंग जिस पर टेस्ट फेल हुआ) मिलेगा।