टेस्ट जनरेटर


टेस्ट जनरेटर एक ट्रैक-विशिष्ट सॉफ्टवेयर होता है, जो किसी प्रैक्टिस अभ्यास के टेस्ट अपने आप बना देता है। यह अभ्यास के JSON टेस्ट केसों को ट्रैक की भाषा के टेस्ट में बदलकर ऐसा करता है।

लाभ

टेस्ट जनरेटर होने के कुछ लाभ ये हैं:

  1. अभ्यास तेज़ी से जोड़े जा सकते हैं
  2. अभ्यास जोड़ने के "उबाऊ" हिस्सों को अपने आप कर देता है
  3. टेस्ट को नवीनतम कैनोनिकल डेटा के साथ सिंक करना आसान होता है

उपयोग के मामले

आम तौर पर टेस्ट जनरेटर इन दो में से किसी एक काम के लिए चलाया जाता है:

  1. किसी नए अभ्यास के टेस्ट बनाने के लिए
  2. किसी मौजूदा अभ्यास के टेस्ट अपडेट करने के लिए

नए अभ्यास के लिए टेस्ट बनाना

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

मौजूदा अभ्यास के टेस्ट अपडेट करना

किसी अभ्यास में टेस्ट जनरेटर आ जाने के बाद, आप उसे दोबारा चलाकर अभ्यास को उसके नवीनतम कैनोनिकल डेटा के साथ अपडेट या सिंक कर सकते हैं। हमारा सुझाव है कि आप समय-समय पर ऐसा करें, ताकि देख सकें कि कहीं कोई ऐसा टेस्ट केस तो नहीं जिसे अपडेट करना ज़रूरी है, या कोई नया टेस्ट जिसे आप शामिल करना चाहते हैं।

शुरुआत का बिंदु

किसी अभ्यास के लिए टेस्ट जनरेटर बनाते समय शुरुआत दो जगह से हो सकती है:

  1. अभ्यास नया है, इसलिए उसके कोई टेस्ट नहीं हैं
  2. अभ्यास पहले से मौजूद है, इसलिए उसके कुछ टेस्ट पहले से हैं
Caution

अगर टेस्ट पहले से मौजूद हैं, तो टेस्ट जनरेटर ऐसे बनाइए कि उससे बनने वाले टेस्ट मौजूदा हल न तोड़ें।

डिज़ाइन

मोटे तौर पर, टेस्ट फाइलें इन दो तरीकों से बनाई जाती हैं:

  • कोड: टेस्ट फाइलें (ज़्यादातर) कोड के ज़रिए बनाई जाती हैं
  • टेम्पलेट: टेस्ट फाइलें (ज़्यादातर) टेम्पलेट की मदद से बनाई जाती हैं

हमने देखा है कि कोड आधारित तरीके में टेस्ट जनरेटर का कोड काफी जटिल हो जाता है, जबकि टेम्पलेट आधारित तरीका आसान होता है।

हम यह क्रम अपनाने का सुझाव देते हैं:

  1. अभ्यास का कैनोनिकल डेटा पढ़िए
  2. अभ्यास की tests.toml फाइल में include = false के रूप में चिह्नित टेस्ट केसों को छोड़ दीजिए
  3. अभ्यास के कैनोनिकल डेटा को ऐसे प्रारूप में बदलिए जिसका टेम्पलेट में उपयोग किया जा सके
  4. अभ्यास के कैनोनिकल डेटा को अभ्यास-विशिष्ट टेम्पलेट को सौंपिए

इस व्यवस्था का मुख्य लाभ यह है कि हर अभ्यास का अपना टेम्पलेट होता है, जो:

  • यह साफ कर देता है कि टेस्ट फाइलें कैसे बनती हैं
  • इन्हें डीबग करना आसान बनाता है
  • इन्हें किसी दूसरे अभ्यास के टूटने के डर के बिना बदलना सुरक्षित बनाता है
Caution

टेस्ट जनरेटर डिज़ाइन करते समय कोशिश कीजिए कि:

  • टेस्ट जनरेटर के अंदर कैनोनिकल डेटा की प्री-प्रोसेसिंग कम से कम हो
  • टेम्पलेट के बीच जुड़ाव कम हो

कार्यान्वयन

टेस्ट जनरेटर आमतौर पर (ज़्यादातर) ट्रैक की भाषा में ही लिखा जाता है।

Caution

आप दूसरी भाषाएँ इस्तेमाल करने के लिए स्वतंत्र हैं, लेकिन हर अतिरिक्त भाषा ट्रैक को बनाए रखना या उसमें योगदान देना और मुश्किल बना देती है। इसलिए हमारा सुझाव है कि जहाँ संभव हो, ट्रैक की भाषा ही इस्तेमाल कीजिए, क्योंकि इससे उसे बनाए रखना और उसमें योगदान देना आसान हो जाता है।

फॉर्मैटिंग

अगर आपके ट्रैक में कोड फॉर्मैट करने का टूल है, तो टेम्पलेट रेंडर करने के बाद इसे पोस्ट-प्रोसेसिंग के तौर पर चलाने पर विचार कीजिए।

कैनोनिकल डेटा

टेस्ट जनरेटर जिस मुख्य डेटा के साथ काम करता है, वह अभ्यास की canonical-data.json फाइल है। यह फाइल exercism/problem-specifications रिपॉज़िटरी में परिभाषित होती है, जो Exercism के कई अभ्यासों के लिए साझा मेटाडेटा तय करती है।

Caution

सभी अभ्यासों में canonical-data.json फाइल नहीं होती! जिन अभ्यासों में यह नहीं होती, उनके टेस्ट आपको खुद बनाने पड़ेंगे, क्योंकि टेस्ट जनरेटर के काम करने के लिए कोई डेटा ही नहीं होगा।

संरचना

कैनोनिकल डेटा एक JSON ऑब्जेक्ट में परिभाषित होता है। इस ऑब्जेक्ट में एक "cases" फील्ड होता है, जिसमें टेस्ट केस होते हैं। ये टेस्ट केस (आमतौर पर) आपके ट्रैक के टेस्ट से एक-से-एक मेल खाते हैं।

हर टेस्ट केस में कुछ प्रॉपर्टी होती हैं, जिनमें description, property, input वैल्यू और expected वैल्यू सबसे ज़रूरी होती हैं। यहाँ लीप अभ्यास की canonical-data.json फाइल का एक (आंशिक) उदाहरण है:

{
  "exercise": "leap",
  "cases": [
    {
      "uuid": "6466b30d-519c-438e-935d-388224ab5223",
      "description": "year not divisible by 4 in common year",
      "property": "leapYear",
      "input": {
        "year": 2015
      },
      "expected": false
    },
    {
      "uuid": "4fe9b84c-8e65-489e-970b-856d60b8b78e",
      "description": "year divisible by 4, not divisible by 100 in leap year",
      "property": "leapYear",
      "input": {
        "year": 1996
      },
      "expected": true
    }
  ]
}

टेस्ट जनरेटर की मुख्य ज़िम्मेदारी इस JSON डेटा को ट्रैक-विशिष्ट टेस्ट में बदलना है। ऊपर का JSON Nim टेस्ट कोड में ऐसे बदला जा सकता है:

import unittest
import leap

suite "Leap":
  test "year not divisible by 4 in common year":
    check isLeapYear(2015) == false

  test "year divisible by 4, not divisible by 100 in leap year":
    check isLeapYear(1996) == true

canonical-data.json फाइल की संरचना को अच्छी तरह से डॉक्युमेंट किया गया है, और उसकी एक JSON स्कीमा परिभाषा भी है।

नेस्टिंग

कुछ अभ्यासों में उनके कैनोनिकल डेटा में नेस्टिंग का उपयोग होता है। इसका मतलब है कि cases ऐरे का हर एलिमेंट इन दो में से एक हो सकता है:

  1. एक सामान्य टेस्ट केस (जिसमें कोई चाइल्ड टेस्ट केस नहीं)
  2. टेस्ट केसों का एक समूह (एक या अधिक चाइल्ड टेस्ट केस)
Note

किसी एलिमेंट का प्रकार यह देखकर पहचाना जा सकता है कि उसमें ऐसी फील्ड हैं या नहीं जो सिर्फ एक ही प्रकार के एलिमेंट में आती हैं। ऐसा करने का सबसे अच्छा तरीका शायद "cases" कुंजी का उपयोग करना है, जो सिर्फ टेस्ट केस समूहों में ही होती है।

यहाँ नेस्टेड टेस्ट केसों का एक उदाहरण है:

{
  "cases": [
    {
      "uuid": "e9c93a78-c536-4750-a336-94583d23fafa",
      "description": "data is retained",
      "property": "data",
      "input": {
        "treeData": ["4"]
      },
      "expected": {
        "data": "4",
        "left": null,
        "right": null
      }
    },
    {
      "description": "insert data at proper node",
      "cases": [
        {
          "uuid": "7a95c9e8-69f6-476a-b0c4-4170cb3f7c91",
          "description": "smaller number at left node",
          "property": "data",
          "input": {
            "treeData": ["4", "2"]
          },
          "expected": {
            "data": "4",
            "left": {
              "data": "2",
              "left": null,
              "right": null
            },
            "right": null
          }
        }
      ]
    }
  ]
}
Caution

अगर आपका ट्रैक टेस्ट को समूहों में बाँटना नहीं देता, तो आपको यह करना होगा:

  • cases पदानुक्रम को पार करना या चपटा करना, ताकि अंत में सिर्फ सबसे अंदर वाले (लीफ) टेस्ट केस ही बचें
  • एक अनोखा टेस्ट नाम बनाने के लिए टेस्ट केस के description को उसके पैरेंट description के साथ जोड़ना

इनपुट और अपेक्षित वैल्यू

टेस्ट केस की input और expected कुंजियों में जो होता है, वह बहुत अलग-अलग तरह का होता है। ज़्यादातर मामलों में ये स्केलर वैल्यू (जैसे संख्याएँ, बूलियन या स्ट्रिंग) या साधारण ऑब्जेक्ट होती हैं। लेकिन कभी-कभी ऐसी ज़्यादा जटिल वैल्यू भी मिलती हैं, जिनके लिए थोड़ी प्री-प्रोसेसिंग की ज़रूरत पड़ सकती है, जैसे स्यूडो कोड में लैम्ब्डा, छात्र के कोड पर करने वाले ऑपरेशनों की सूची, और भी बहुत कुछ।

परिदृश्य

टेस्ट केसों में एक वैकल्पिक scenarios फील्ड होता है। टेस्ट जनरेटर इस फील्ड का उपयोग कुछ खास टेस्ट केसों को अलग तरीके से संभालने के लिए कर सकता है। सबसे आम उपयोग यह है कि कुछ तरह के टेस्ट छोड़ दिए जाएँ, जैसे "unicode" परिदृश्य वाले टेस्ट, क्योंकि आपके ट्रैक की भाषा शायद Unicode सपोर्ट न करती हो।

परिदृश्यों की पूरी सूची यहाँ मिल जाएगी।

canonical-data.json फाइलें पढ़ना

canonical-data.json फाइलें पढ़ने के कुछ विकल्प हैं:

  1. इन्हें सीधे problem-specifications रिपॉज़िटरी से लाइए (जैसे https://raw.githubusercontent.com/exercism/problem-specifications/main/exercises/leap/canonical-data.json)।
  2. problem-specifications रेपो को ट्रैक रेपो में Git सबमॉड्यूल के तौर पर जोड़िए।
  3. इन्हें configlet कैश से पढ़िए। इसकी जगह उपयोगकर्ता के सिस्टम पर निर्भर करती है, लेकिन जगह प्रोग्राम के ज़रिए पाने के लिए आप configlet info -o -v d | head -1 | cut -d " " -f 5 चला सकते हैं।

ट्रैक-विशिष्ट टेस्ट केस

अगर आपका ट्रैक कुछ अतिरिक्त, ट्रैक-विशिष्ट टेस्ट केस जोड़ना चाहता है (जो कैनोनिकल डेटा में नहीं मिलते), तो एक विकल्प यह है कि आप एक additional-test-cases.json फाइल बनाइए। इसके बाद टेस्ट जनरेटर उसे रेंडरिंग के लिए टेम्पलेट को सौंपने से पहले canonical-data.json फाइल के साथ मिला सकता है।

टेम्पलेट

जो टेम्पलेट इंजन इस्तेमाल होगा, वह शायद ट्रैक-विशिष्ट ही होगा। आदर्श रूप से आप चाहेंगे कि आपके टेम्पलेट जितने सीधे-सरल हो सकें, उतने हों, इसलिए कोड डुप्लीकेशन जैसी चीज़ों की चिंता न कीजिए।

टेम्पलेट अपना डेटा टेस्ट जनरेटर से लेते हैं, और रेंडर करने के लिए उसी डेटा पर इटरेशन करते हैं।

Note

टेम्पलेट को सरल रखने में मदद के लिए यह अच्छा रहेगा कि टेस्ट जनरेटर की तरफ थोड़ी प्री-प्रोसेसिंग कर ली जाए, या फिर कुछ "फिल्टर" बना लिए जाएँ, या आपके टेम्पलेट जो भी एक्सटेंशन का तरीका देते हों, वह इस्तेमाल किया जाए।

configlet का उपयोग

configlet ट्रैक बनाए रखने का मुख्य टूल है और इसका उपयोग इन कामों के लिए किया जा सकता है:

  • नए अभ्यास के लिए अभ्यास फाइलें बनाना: bin/configlet create --practice-exercise <slug> चलाइए
  • मौजूदा अभ्यास की tests.toml फाइल सिंक करना: bin/configlet sync --tests --update --exercise <slug> चलाइए
  • अभ्यास का कैनोनिकल डेटा डिस्क पर लाना (यह ऊपर दी गई दोनों में से किसी भी कमांड का साइड-इफेक्ट है)

इसी वजह से configlet टेस्ट जनरेटर के साथ मिलाकर बहुत काम के वर्कफ्लो बनाने के लिए शानदार टूल है।

कमांड-लाइन इंटरफेस

आप चाहेंगे कि टेस्ट जनरेटर का इस्तेमाल आसान भी हो और शक्तिशाली भी। इसके लिए हम एक या अधिक स्क्रिप्ट फाइलें बनाने का सुझाव देते हैं।

Note

आप कोई भी स्क्रिप्ट फाइल फॉर्मैट चुन सकते हैं, जो आपके ट्रैक के लिए सबसे अच्छा बैठे। Shell स्क्रिप्ट और PowerShell स्क्रिप्ट आम विकल्प हैं, और दोनों अच्छी तरह काम कर सकते हैं।

यहाँ एक shell स्क्रिप्ट का उदाहरण है, जो configlet और टेस्ट जनरेटर को मिलाकर नया अभ्यास जल्दी से बना देती है:

bin/fetch-configlet
bin/configlet create --practice-exercise <slug>
path/to/test-generator <slug>

शुरू से बनाना

टेस्ट जनरेटर बनाना शुरू करने से पहले हमारा सुझाव है कि आप कुछ मौजूदा टेस्ट जनरेटर देख लें, ताकि अंदाज़ा हो जाए कि दूसरे ट्रैक ने इन्हें कैसे बनाया है:

अगर आपके कोई सवाल हैं, तो उन्हें पूछने की सबसे अच्छी जगह फोरम है। Rust टेस्ट जनरेटर के बारे में और JavaScript टेस्ट जनरेटरों पर हुई फोरम चर्चाएँ भी आपके काम आ सकती हैं।

न्यूनतम व्यवहार्य उत्पाद

हमारा सुझाव है कि टेस्ट जनरेटर को थोड़ा-थोड़ा करके बनाइए, और शुरुआत न्यूनतम व्यवहार्य उत्पाद से कीजिए। सबसे बुनियादी वर्ज़न बस इतना करेगा कि वह अभ्यास की canonical-data.json पढ़े और उस डेटा को सीधे टेम्पलेट को सौंप दे।

शुरुआत एक ही अभ्यास पर ध्यान देकर कीजिए, और बेहतर होगा कि वह leap जैसा आसान अभ्यास हो। जब वह काम करने लगे, तभी धीरे-धीरे और अभ्यास जोड़िए।

और टेस्ट जनरेटर को जितना सरल रख सकें, उतना सरल रखने की कोशिश कीजिए।

Note

आदर्श रूप से एक योगदानकर्ता बिना यह समझे कि टेस्ट जनरेटर अंदर से कैसे काम करता है, किसी मौजूदा टेम्पलेट को चिपका या बदल सके।

उपयोग करना या योगदान देना

किसी टेस्ट जनरेटर का इस्तेमाल कैसे करें या उसमें योगदान कैसे दें, यह ट्रैक पर निर्भर करता है। निर्देश ट्रैक की README.md, CONTRIBUTING.md या टेस्ट जनरेटर के कोड वाली डायरेक्टरी में देखिए।