בדיקות יחידה

לאחר שינוי או הוספה של קוד, עליכם להריץ בדיקות יחידה קיימות ולשקול לכתוב יותר. כל הבדיקות מתבצעות בגרסאות הלא דחוסות של הקוד.

יש שתי קבוצות של בדיקות יחידה: בדיקות JS ובדיקות של מחולל בלוקים.

בדיקות JS

בדיקות ה-JS מאשרות את הפעולה של פונקציות JavaScript פנימיות בפלטפורמה של Blockly בליבה. אנחנו משתמשים ב-Mocha כדי להריץ בדיקות יחידה, ב-Sinon כדי ליצור stubs של יחסי תלות וב-Chai כדי לבצע טענות נכוֹנוּת לגבי הקוד.

הרצת בדיקות

גם ב-blockly וגם ב-blockly-samples, npm run test ירוץ את בדיקות היחידה. לחשבון באופן מוגבל, תריצו גם בדיקות אחרות כמו איתור שגיאות בקוד (linting) והידור. אפשר לפתוח גם את tests/mocha/index.html בדפדפן כדי להריץ באופן אינטראקטיבי את כל מוצרי מוקה בדיקות.

מבחני כתיבה

אנחנו משתמשים בממשק Mocha TDD כדי להריץ בדיקות. הבדיקות מסודרות בסוויטות, שיכולים להכיל יחידות משנה נוספות או בדיקות. באופן כללי, כל התאמה של לרכיב של Blockly (כמו toolbox או workspace) יש קובץ בדיקה משלו שכולל חבילה אחת או יותר. בכל סוויטה יכולים להיות setup ו-teardown שלא תיקרא לפני ואחריה, בהתאמה, כל בדיקה סוויטה.

כלי עזר לבדיקות

יש לנו כמה פונקציות עזר ספציפיות ל-Blockly שיכולות להיות שימושיות כשכותבים בדיקות. ניתן למצוא את השפות האלה core ובתוך blockly-samples.

פונקציות העזרה כוללות את sharedTestSetup ו-sharedTestTeardown, שחובה להפעיל לפני ואחרי הבדיקות (ראו הקטע 'דרישות').

sharedTestSetup:
  • הגדרת טיימרים sinon fake טיימרים (בחלק מהבדיקות תצטרכו להשתמש) this.clock.runAll).
  • סטאבים של Blockly.Events.fire כדי להפעיל מיד (ניתן להגדרה).
  • הגדרת ניקוי אוטומטי של blockTypes שהוגדרו באמצעות defineBlocksWithJsonArray.
  • מצהירה על מספר מאפיינים בהקשר של this שאמורים להיות נגיש:
    • this.clock (אבל לא צריך לשחזר אותו, אחרת הוא יגרום לבעיות ב-sharedTestTeardown)
    • this.eventsFireStub
    • this.sharedCleanup (לשימוש עם addMessageToCleanup וגם addBlockTypeToCleanup) (הערה: אין צורך להשתמש במודל הזה addBlockTypeToCleanup אם הגדרתם את הבלוק באמצעות defineBlocksWithJsonArray)

לפונקציה יש פרמטר options אופציונלי אחד להגדרת ההגדרה. נכון לעכשיו, הוא משמש רק כדי לקבוע אם להשפיע על Blockly.Events.fire כדי לירות מיד (ייעלם כברירת מחדל).

sharedTestTeardown:
  • הפונקציה מנקה את סביבת העבודה this.workspace (בהתאם למיקום שבו היא הוגדרה, מידע נוסף זמין בקטע 'דרישות הבדיקה').
  • שחזור של כל ה-stubs.
  • ניקוי כל סוגי הבלוקים שנוספו דרך 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) ב-teardown של הסוויטה הפנימית הזו.

מבנה הבדיקה

בדרך כלל, בדיקות יחידה פועלות לפי מבנה קבוע שאפשר לסכם בתור ארגון, פעולה, טענת נכוֹנוּת.

  1. ארגון: מגדירים את מצב העולם ואת כל התנאים הנדרשים כדי בהתנהגות הנבדקת.
  2. פעולה: קוראים לקוד שנבדק כדי להפעיל את ההתנהגות שנבדקת.
  3. טענת נכוֹנוּת (assertion): הצגת טענות נכונות (assertions) לגבי הערך המוחזר או אינטראקציות עם חיקויים כדי לאמת את נכונותו.

בבדיקה פשוטה, ייתכן שלא תהיה התנהגות שצריך לארגן, והפעולה ניתן לשלב שלבי הצהרה על ידי הטמעת הקריאה החוזרת לקוד הנבדק טענת נכוֹנוּת (assertion). במקרים מורכבים יותר, הבדיקות יהיו קריאות יותר אם לא מפסיקים לשלושת השלבים האלה.

הנה קובץ בדיקה לדוגמה (פשוט מהדבר האמיתי).

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 נוספים שיטות.
  • לכל חבילה ובדיקה יש שם תיאורי.
  • טענות נכוֹנוּת (assertion) של Chai משמשות לטענות נכונות (assertions) לגבי הקוד.
    • אפשר לספק ארגומנט מחרוזת אופציונלי שיוצג אם הבדיקה תיכשל. כך קל יותר לנפות באגים בבדיקות לא תקינות.
    • סדר הפרמטרים הוא chai.assert.equal(actualValue, expectedValue, optionalMessage). אם מחליפים בין actual לבין expected, הודעות השגיאה לא יישמעו הגיוניות.
  • משתמשים ב-Sinon כדי ליצור סטאבים של שיטות כשלא רוצים לקרוא לקוד האמיתי. בדוגמה הזו, אנחנו לא רוצים להפעיל את פונקציית המדדים האמיתית כי היא לא רלוונטית לבדיקה הזו. אנחנו מתעניינים רק באופן שבו השיטה שנבדקת משתמשת בתוצאות. ‏Sinon יוצר סטאבים לפונקציה getMetrics כדי להחזיר תשובה מוכנה מראש, שאנחנו יכולים לבדוק בקלות בטענות הנכוֹנוּת (assertions) של הבדיקות.
  • השיטות 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. בתפריט הנפתח, בוחרים את החלק הרלוונטי של המערכת שרוצים לבדוק. לוחצים על 'טעינה'. ב-Workspace אמורים להופיע בלוקים.
  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. לוחצים על XML.
  5. מעתיקים את ה-XML שנוצר לקובץ המתאים ב-tests/generators/.