اختبارات الوحدة

بعد تغيير الرمز أو إضافته، يجب إجراء اختبارات الوحدة الحالية والنظر في وكتابة المزيد. يتم تنفيذ جميع الاختبارات على الإصدارات غير المضغوطة من الرمز البرمجي.

هناك مجموعتان من اختبارات الوحدات: اختبارات JavaScript واختبارات أداة إنشاء الكتل.

اختبارات JavaScript

تؤكد اختبارات JavaScript تشغيل دوال JavaScript الداخلية في نافذة الأساسية. نستخدم Mocha لتشغيل اختبارات الوحدة، Sinon لإنشاء نماذج اصطناعية للتبعيات، Chai لإجراء تأكيدات حول الرمز البرمجي.

الاختبارات الجارية

في كلّ من blockly وblockly-samples، سيُجري npm run test اختبارات الوحدات. ضِمن بشكل مكعّب، سيؤدي ذلك أيضًا إلى إجراء اختبارات أخرى مثل استخدام أداة Lint وتجميع. يمكنك أيضًا فتح tests/mocha/index.html في متصفّح لتشغيل جميع رموز mocha بشكل تفاعلي الاختبار.

اختبارات الكتابة

نستخدم واجهة Mocha TDD لإجراء الاختبارات. يتم تنظيم الاختبارات في مجموعات، والتي يمكن أن تحتوي على مجموعات فرعية و/أو اختبارات إضافية. بشكل عام، يحتوي كل مكوّن من مكوّنات Blockly (مثل toolbox أو workspace) على ملف اختبار خاص به يحتوي على مجموعة واحدة أو أكثر. يمكن أن تحتوي كل مجموعة على setup وteardown طريقة سيتم استدعاؤها قبل كل اختبار في تلك المجموعة وبعده على التوالي.

أدوات المساعدة للاختبار

لدينا عدد من الدوال المساعدة الخاصة بـ Blockly والتي قد تكون مفيدة عندما وكتابة الاختبارات. يمكن العثور عليها في الأساسية وفي العيّنات المحظورة

تشمل الدوال المساعدة sharedTestSetup وsharedTestTeardown اللذين مطلوبة ليتم طلبها قبل إجراء الاختبارات وبعدها (انظر "المتطلبات" ).

sharedTestSetup:
  • لإعداد موقّتات وهمية في مكتبة sinon (في بعض الاختبارات، ستحتاج إلى استخدام this.clock.runAll).
  • Stubs Blockly.Events.fire يتم تنشيطها على الفور (قابل للضبط).
  • لإعداد عملية تنظيف تلقائية لأنواع الحظر المحدّدة من خلال defineBlocksWithJsonArray.
  • تُعلن عن بعض السمات في سياق this التي يُفترض أن تكون متاحة:
    • this.clock (ولكن يجب عدم استعادتها وإلا سيؤدي ذلك إلى حدوث مشاكل في sharedTestTeardown)
    • this.eventsFireStub
    • this.sharedCleanup (تُستخدم مع addMessageToCleanup addBlockTypeToCleanup) (ملاحظة: لست بحاجة إلى استخدام addBlockTypeToCleanup إذا حددت الحظر باستخدام defineBlocksWithJsonArray)

تحتوي الدالة على مَعلمة 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" للمرة الأولى في مجموعة داخلية (أي أنك لم تحددها في المجموعة الخارجية)، يجب عليك يدويًا تخلص منها من خلال طلب workspaceTeardown.call(this, this.workspace) في تقسيم هذا الجناح.
    • إذا حدّدت this.workpace في المجموعة الخارجية، ثم أعدت تعريفها مجموعة اختبار داخلية، فيجب عليك أولاً الاتصال workspaceTeardown.call(this, this.workspace) قبل إعادة تحديده لهدم مساحة العمل الأصلية المحددة في جناح المستوى الأعلى. عليك أيضًا التخلص من القيمة الجديدة يدويًا من خلال استدعاء workspaceTeardown.call(this, this.workspace) مرة أخرى في عملية إزالة هذه المجموعة الداخلية.

بنية الاختبار

تتبع اختبارات الوحدات بشكل عام هيكل محدد، يمكن تلخيصه في وترتيبها وتنفيذها وتأكيدها

  1. ترتيب: عليك إعداد الحالة العالمية وأي شروط ضرورية السلوك قيد الاختبار.
  2. التنفيذ: عليك استدعاء الرمز قيد الاختبار لتشغيل السلوك الذي يتم اختباره.
  3. التأكيد: يمكنك إجراء تأكيدات حول القيمة المعروضة أو التفاعلات مع العناصر التي تمّت محاكاتها للتحقّق من صحتها.

في الاختبار البسيط، قد لا يكون هناك أي سلوك لترتيبه، ويمكن دمج مرحلتي الإجراء والعبارة باستخدام تضمين الطلب إلى الرمز البرمجي الذي يخضع للاختبار في العبارة. في الحالات الأكثر تعقيدًا، ستكون اختباراتك أكثر سهولة في القراءة إذا التزمت بهذه المراحل الثلاث.

في ما يلي مثال على ملف اختبار (مبسّط عن الملف الحقيقي).

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، لن تكون رسائل الخطأ منطقية.
  • يتم استخدام Sinon كاستجابة بديلة عندما لا تريد استدعاء الرمز الحقيقي. ضِمن هذا المثال، لا نريد استدعاء دالة المقاييس الحقيقية لأنها غير ذي صلة بهذا الاختبار. نحن نهتم فقط بكيفية استخدام النتائج من قبل الطريقة قيد الاختبار. يعتمد سينون الدالة 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. حمِّل tests/generators/index.html في Firefox أو Safari. يُرجى العِلم أنّ Chrome وOpera يحتويان على قيود أمان تمنع تحميل الاختبارات من نظام "file://" الملفّات المحلي (المشكلتان 41024 و47416).
  2. اختَر الجزء ذي الصلة من النظام المطلوب اختباره من القائمة المنسدلة، ثم انقر على "تحميل". من المفترض أن تظهر الكتل في مساحة العمل.
  3. انقر على "JavaScript".
    انسخ الرمز الذي تم إنشاؤه وشغِّله في وحدة تحكّم JavaScript. في حال انتهاء الناتج عند الحصول على "حسنًا"، انتهى الاختبار.
  4. انقر على "Python".
    انسخ الرمز الذي تم إنشاؤه وشغِّله في مُفسِّر Python. إذا انتهت النتيجة بكلمة "حسنًا"، يعني ذلك أنّك اجتزت الاختبار.
  5. انقر على "PHP".
    انسخ الرمز الذي تم إنشاؤه وشغِّله في مُفسِّر PHP. إذا انتهت النتيجة بـ "OK"، يعني هذا أنه تم اجتياز الاختبار.
  6. انقر على "Lua".
    انسخ الرمز الذي تم إنشاؤه وشغِّله في مُفسِّر Lua. إذا انتهت النتيجة بـ "OK"، يعني هذا أنه تم اجتياز الاختبار.
  7. انقر على "Dart".
    انسخ الرمز الذي تم إنشاؤه وشغِّله في مترجم سهم. إذا انتهت النتيجة بكلمة "حسنًا"، يعني ذلك أنّك اجتزت الاختبار.

تعديل اختبارات منشئ الحظر

  1. تحميل tests/generators/index.html في متصفّح
  2. اختر الجزء ذا الصلة في النظام من القائمة المنسدلة، وانقر فوق "تحميل". من المفترض أن تظهر الكتل في مساحة العمل.
  3. أجرِ أي تغييرات أو إضافات على الوحدات.
  4. انقر على "XML".
  5. انسخ ملف XML الذي تم إنشاؤه إلى الملف المناسب في tests/generators/.