שימוש ב-Hypothesis למציאה אוטומטית של מקרי קצה בבדיקות יחידה

כאשר כותבים בדיקות יחידה (unit tests) עבור הקוד שלנו, רוב הבדיקות בנויות כך:

  1. הגדרת המידע עליו ירוץ הקוד הנבדק.
  2. הרצת הקוד הנבדק על המידע.
  3. וידוא נכונות הפלט ע"י assertions כלשהם.

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

מה אם יכולנו להפחית את המקרים האלו ע"י שינוי מבנה הבדיקה למשהו כזה:

  1. הגדרת מרחב הקלטים האפשריים עליו ירוץ הקוד הנבדק.
  2. הרצת הקוד על כל אחד מהקלטים האלו בצורה אוטומטית.
  3. וידוא נכונות הפלט ע"י assertions כלשהם.

ספריית Hypothesis מאפשרת לנו לעשות בדיוק את זה!

לדוגמה, נניח שאנחנו רוצים לבדוק פונקציית encode ו-decode כלשהן שכתבנו:

def my_encode(value):
    """ return an encoded value """

def my_decode(decoded_value):
    """ return a decoded value """

אחת הבדיקות יכולה לוודא שהרצת encode על מחרוזת כלשהי, ולאחר מכן decode על הערך המקודד, תחזיר את תמיד המחרוזת המקורית. ספריית Hypothesis מאפשרת לנו לכתוב את הבדיקה הבאה, בלי להגדיר בעצמנו אף מקרה קצה:

import unittest
from hypothesis import given
from hypothesis.strategies import text

class TestEncoding(unittest.TestCase):
    @given(text())
    def test_decode_inverts_encode(self, value):
        self.assertEqual(decode(encode(value)), value)

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

כדי להפוך את הבדיקות שלנו לאיתנות יותר, הספרייה מספקת כמה שירותים נוספים:

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

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

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *