यूनिट की जांच

कोड में बदलाव करने या उसे जोड़ने के बाद, आपको मौजूदा यूनिट टेस्ट चलाने चाहिए और ज़्यादा लिखने के बारे में सोचना चाहिए. सभी जांच, कोड के कंप्रेस न किए गए वर्शन पर की जाती हैं.

यूनिट टेस्ट के दो सेट होते हैं: JS टेस्ट और ब्लॉक जनरेटर टेस्ट.

JS टेस्ट

JS टेस्ट से, Blockly के कोर में मौजूद JavaScript फ़ंक्शन के काम करने की पुष्टि होती है. हम यूनिट टेस्ट चलाने के लिए Mocha, डिपेंडेंसी को स्टब करने के लिए Sinon, और कोड के बारे में दावे करने के लिए Chai का इस्तेमाल करते हैं.

टेस्ट चलाना

blockly और blockly-samples, दोनों में npm run test यूनिट टेस्ट चलाएगा. ब्लॉकली में, लिंटिंग और कंपाइलेशन जैसे दूसरे टेस्ट भी किए जाएंगे. ब्राउज़र में tests/mocha/index.html खोलकर भी, सभी mocha टेस्ट इंटरैक्टिव तरीके से चलाए जा सकते हैं.

राइटिंग टेस्ट

हम जांच करने के लिए, Mocha TDD इंटरफ़ेस का इस्तेमाल करते हैं. टेस्ट को सुइट में व्यवस्थित किया जाता है. इनमें अन्य सब-सुइट और/या टेस्ट, दोनों शामिल हो सकते हैं. आम तौर पर, Blockly के हर कॉम्पोनेंट (जैसे, toolbox या workspace) की अपनी टेस्ट फ़ाइल होती है. इसमें एक या उससे ज़्यादा सुइट होते हैं. हर सुइट के लिए, एक setup और teardown तरीका इस्तेमाल किया जा सकता है. सुइट में, हर टेस्ट से पहले और बाद में ऐसा किया जाता है.

टेस्ट हेल्पर

हमारे पास Blockly के लिए कई सहायक फ़ंक्शन हैं, जो टेस्ट लिखते समय काम आ सकते हैं. ये core और blockly-samples में मिल सकते हैं.

हेल्पर फ़ंक्शन में sharedTestSetup और sharedTestTeardown शामिल हैं. इन्हें जांच से पहले और बाद में कॉल करना ज़रूरी है. ज़रूरी शर्तें वाला सेक्शन देखें.

sharedTestSetup:
  • सिनन नकली टाइमर सेट अप करता है (कुछ टेस्ट में आपको this.clock.runAll का इस्तेमाल करना होगा).
  • Stubs Blockly.Events.fire तुरंत फ़ायर करने के लिए कॉन्फ़िगर करता है.
  • defineBlocksWithJsonArray के ज़रिए तय किए गए blockTypes को अपने-आप हटाने की सुविधा सेट अप करता है.
  • this कॉन्टेक्स्ट में कुछ ऐसी प्रॉपर्टी का एलान करता है जिन्हें ऐक्सेस किया जा सकता है:
    • this.clock (हालांकि, इसे वापस नहीं लाया जाना चाहिए, क्योंकि इससे sharedTestTeardown में समस्याएं हो सकती हैं)
    • this.eventsFireStub
    • this.sharedCleanup (addMessageToCleanup और addBlockTypeToCleanup के साथ इस्तेमाल किया जाना चाहिए) (ध्यान दें: अगर आपने defineBlocksWithJsonArray का इस्तेमाल करके ब्लॉक तय किया है, तो आपको addBlockTypeToCleanup का इस्तेमाल करने की ज़रूरत नहीं है)

सेटअप कॉन्फ़िगर करने के लिए, फ़ंक्शन में एक वैकल्पिक options पैरामीटर होता है. फ़िलहाल, इसका इस्तेमाल सिर्फ़ यह तय करने के लिए किया जाता है कि Blockly.Events.fire को तुरंत ट्रिगर करने के लिए स्टब किया जाए या नहीं (डिफ़ॉल्ट रूप से स्टब किया जाएगा).

sharedTestTeardown:
  • फ़ाइल फ़ोल्डर this.workspace को हटा देता है. यह इस बात पर निर्भर करता है कि फ़ाइल फ़ोल्डर को कहां सेट किया गया था. ज़्यादा जानकारी के लिए, जांच की ज़रूरी शर्तें सेक्शन देखें.
  • सभी स्टब को वापस लाता है.
  • defineBlocksWithJsonArray और addBlockTypeToCleanup की मदद से जोड़े गए सभी तरह के ब्लॉक हटाता है.
  • addMessageToCleanup के ज़रिए जोड़े गए सभी मैसेज मिटा दिए जाते हैं.

टेस्ट से जुड़ी ज़रूरी शर्तें

  • हर टेस्ट में, सबसे बाहरी सुइट के सेटअप में पहली लाइन के तौर पर sharedTestSetup.call(this); और किसी फ़ाइल के लिए सबसे बाहरी सुइट के टियरडाउन में आखिरी लाइन के तौर पर sharedTestTeardown.call(this); को कॉल करना ज़रूरी है.
  • अगर आपको सामान्य टूलबॉक्स वाला वर्कस्पेस चाहिए, तो टेस्ट index.html पर मौजूद पहले से सेट टूलबॉक्स में से किसी एक का इस्तेमाल किया जा सकता है. उदाहरण के लिए, नीचे देखें.
  • this.workspace को सही तरीके से नष्ट करें. ज़्यादातर टेस्ट में, सबसे बाहरी सुइट में this.workspace को तय किया जाता है और बाद के सभी टेस्ट में इसका इस्तेमाल किया जाता है. हालांकि, कुछ मामलों में इनर सुइट में इसे परिभाषित या फिर से परिभाषित किया जा सकता है. उदाहरण के लिए, किसी टेस्ट को ऐसे फ़ाइल फ़ोल्डर की ज़रूरत होती है जिसमें आपके सेट अप से अलग विकल्प हों. जांच खत्म होने के बाद, इसे नष्ट कर देना चाहिए.
    • अगर आपने सबसे बाहरी सुइट में this.workspace को परिभाषित किया है और कभी भी फिर से तय नहीं किया है, तो आपको कुछ और करने की ज़रूरत नहीं है. यह sharedTestTeardown से अपने-आप मिट जाएगा.
    • अगर आपने this.workspace को पहली बार किसी अंदरूनी सुइट में तय किया है (यानी आपने इसे सबसे बाहरी सुइट में तय नहीं किया है), तो आपको उस सुइट के teardown में workspaceTeardown.call(this, this.workspace) को मैन्युअल तरीके से हटाना होगा.
    • अगर आपने सबसे बाहरी सुइट में this.workpace तय किया है, लेकिन फिर उसे किसी अंदरूनी टेस्ट सुइट में फिर से तय किया है, तो आपको सबसे पहले workspaceTeardown.call(this, this.workspace) को फिर से तय करने से पहले कॉल करना होगा. ऐसा, टॉप लेवल सुइट में तय किए गए ओरिजनल वर्कस्पेस को हटाने के लिए करना होगा. आपको इस इनर सुइट के टियरडाउन में, workspaceTeardown.call(this, this.workspace) को फिर से कॉल करके, नई वैल्यू को मैन्युअल तरीके से भी हटाना होगा.

टेस्ट का स्ट्रक्चर

आम तौर पर, यूनिट टेस्ट में एक तय स्ट्रक्चर होता है. इस स्ट्रक्चर की खास जानकारी को व्यवस्थित करें, कार्रवाई करें, दावा करें के तौर पर इस्तेमाल किया जा सकता है.

  1. व्यवस्थित करें: टेस्ट किए जा रहे व्यवहार के लिए, दुनिया की स्थिति और ज़रूरी शर्तें सेट अप करें.
  2. कार्रवाई करें: जांचे जा रहे व्यवहार को ट्रिगर करने के लिए, जांचे जा रहे कोड को कॉल करें.
  3. Assert: सही होने की पुष्टि करने के लिए, रिटर्न वैल्यू या मॉक किए गए ऑब्जेक्ट के साथ होने वाले इंटरैक्शन के बारे में दावा करें.

किसी आसान टेस्ट में, व्यवहार को व्यवस्थित करने की ज़रूरत नहीं पड़ सकती. साथ ही, ऐक्ट और पुष्टि करने के चरणों को एक साथ जोड़ा जा सकता है. इसके लिए, पुष्टि करने के चरण में टेस्ट किए जा रहे कोड के कॉल को इनलाइन करें. ज़्यादा मुश्किल मामलों के लिए, इन तीन चरणों का पालन करने पर, आपके टेस्ट ज़्यादा आसानी से पढ़े जा सकेंगे.

यहां टेस्ट फ़ाइल का एक उदाहरण दिया गया है. इसे असल फ़ाइल से आसान बनाया गया है.

suite('Flyout', function() {
  setup(function() {
    sharedTestSetup.call(this);
    this.toolboxXml = document.getElementById('toolbox-simple');
    this.workspace = Blockly.inject('blocklyDiv',
        {
          toolbox: this.toolboxXml
        });
  });

  teardown(function() {
    sharedTestTeardown.call(this);
  });

  suite('simple flyout', function() {
    setup(function() {
      this.flyout = this.workspace.getFlyout();
    });
    test('y is always 0', function() {
      // Act and assert stages combined for simple test case
      chai.assert.equal(this.flyout.getY(), 0, 'y coordinate in vertical flyout is 0');
    });
    test('x is right of workspace if flyout at right', function() {
      // Arrange
      sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
        viewWidth: 100,
      });
      this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_RIGHT;
      this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_RIGHT;

      // Act
      var x = this.flyout.getX();

      // Assert
      chai.assert.equal(x, 100, 'x is right of workspace');
    });
  });
});

इस उदाहरण से जुड़ी अहम बातें:

  • किसी सुइट में ऐसे अन्य सुइट शामिल हो सकते हैं जिनमें setup और teardown के लिए अतिरिक्त तरीके हों.
  • हर सुइट और टेस्ट का एक ब्यौरा होता है.
  • Chai के दावों का इस्तेमाल, कोड के बारे में दावे करने के लिए किया जाता है.
    • स्ट्रिंग आर्ग्युमेंट के तौर पर एक वैकल्पिक फ़ील्ड दिया जा सकता है. यह तब दिखाया जाएगा, जब जांच फ़ेल हो जाएगी. इससे, गड़बड़ी वाली जांचों को डीबग करना आसान हो जाता है.
    • पैरामीटर का क्रम chai.assert.equal(actualValue, expectedValue, optionalMessage) है. actual और expected को बदलने पर, गड़बड़ी के मैसेज समझ नहीं आएंगे.
  • जब आप असली कोड को कॉल न करना चाहें, तब सिनोन का इस्तेमाल मेथड को स्टब करने के लिए किया जाता है. इस उदाहरण में, हम रीयल मेट्रिक फ़ंक्शन को कॉल नहीं करना चाहते, क्योंकि यह इस टेस्ट के लिए काम का नहीं है. हम सिर्फ़ इस बात पर ध्यान देते हैं कि जांचे जा रहे तरीके से नतीजों का इस्तेमाल कैसे किया जाता है. सिनोन पहले से तैयार जवाब देने के लिए getMetrics फ़ंक्शन को करता है, जिसकी जाँच हम अपने जाँच दावों में आसानी से कर सकते हैं.
  • हर सुइट के लिए, setup के तरीकों में सिर्फ़ सामान्य सेटअप होना चाहिए, जो सभी जांचों पर लागू होता है. अगर किसी खास बिहेवियर के लिए टेस्ट किसी खास शर्त पर निर्भर करता है, तो उस शर्त के बारे में टेस्ट में साफ़ तौर पर बताया जाना चाहिए.

डीबगिंग टेस्ट

  • ब्राउज़र में टेस्ट खोले जा सकते हैं. साथ ही, डेवलपर टूल का इस्तेमाल करके ब्रेकपॉइंट सेट किए जा सकते हैं. इससे यह पता लगाया जा सकता है कि आपके टेस्ट अचानक से फ़ेल हो रहे हैं या अचानक से पास हो रहे हैं!
  • किसी टेस्ट या सुइट पर .only() या .skip() सेट करें, ताकि सिर्फ़ उस टेस्ट का सेट चलाया जा सके या किसी टेस्ट को स्किप किया जा सके. उदाहरण के लिए:

    suite.only('Workspace', function () {
      suite('updateToolbox', function () {
        test('test name', function () {
          // ...
        });
        test.skip('test I don’t care about', function () {
          // ...
        });
      });
    });
    

    कोड को कमिट करने से पहले, इन टिप्पणियों को हटाना न भूलें.

जनरेटर जांच ब्लॉक करें

हर ब्लॉक की अपनी यूनिट टेस्ट होती हैं. इन टेस्ट से यह पुष्टि की जाती है कि ब्लॉक, फ़ंक्शन के मुकाबले सही कोड जनरेट करते हैं.

  1. Firefox या Safari में tests/generators/index.html लोड करें. ध्यान दें कि Chrome और Opera में ऐसी सुरक्षा पाबंदियां हैं जो लोकल "file://" सिस्टम (समस्याएं 41024 और 47416) से टेस्ट लोड करने से रोकती हैं.
  2. ड्रॉप-डाउन मेन्यू से, सिस्टम का वह हिस्सा चुनें जिसकी जांच करनी है. इसके बाद, "लोड करें" पर क्लिक करें. ब्लॉक, वर्कस्पेस में दिखने लगेंगे.
  3. "JavaScript" पर क्लिक करें.
    जनरेट किए गए कोड को JavaScript कंसोल में कॉपी करें और चलाएं. अगर आउटपुट "OK" पर खत्म होता है, तो टेस्ट पास हो गया है.
  4. "Python" पर क्लिक करें.
    जनरेट किए गए कोड को कॉपी करके, Python इंटरप्रेटर में चलाएं. अगर आउटपुट "OK" पर खत्म होता है, तो इसका मतलब है कि जांच पूरी हो गई है.
  5. "PHP" पर क्लिक करें.
    जनरेट किए गए कोड को कॉपी करके, PHP इंटरप्रेटर में चलाएं. अगर आउटपुट "OK" पर खत्म होता है, तो इसका मतलब है कि जांच पूरी हो गई है.
  6. "Lua" पर क्लिक करें.
    जनरेट किए गए कोड को Lua इंटरप्रेटर में कॉपी करके चलाएं. अगर आउटपुट "OK" पर खत्म होता है, तो इसका मतलब है कि जांच पूरी हो गई है.
  7. "Dart" पर क्लिक करें.
    जनरेट किए गए कोड को कॉपी करके, Dart इंटरप्रेटर में चलाएं. अगर आउटपुट "OK" पर खत्म होता है, तो इसका मतलब है कि जांच पूरी हो गई है.

ब्लॉक जनरेटर टेस्ट में बदलाव करना

  1. tests/generators/index.html को ब्राउज़र में लोड करें.
  2. ड्रॉप-डाउन मेन्यू से सिस्टम का काम का हिस्सा चुनें और "लोड करें" पर क्लिक करें. ब्लॉक, वर्कस्पेस में दिखने लगेंगे.
  3. ब्लॉक में कोई बदलाव करें या कोई जानकारी जोड़ें.
  4. "एक्सएमएल" पर क्लिक करें.
  5. जनरेट किए गए एक्सएमएल को tests/generators/ में मौजूद सही फ़ाइल में कॉपी करें.