מחלקות בדיקה ושיטות בדיקה

הושלם

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

בדיוק כמו פונקציות, עדיין תוכל לכתוב קביעות באמצעות assert שלך.

בניית כיתת בדיקה

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

כך נראית הפונקציה:

import os

def is_done(path):
    if not os.path.exists(path):
        return False
    with open(path) as _f:
        contents = _f.read()
    if "yes" in contents.lower():
        return True
    elif "no" in contents.lower():
        return False

כעת, כך נראית כיתה עם שתי בדיקות (אחת עבור כל תנאי) בקובץ בשם test_files.py הבא:

class TestIsDone:

    def test_yes(self):
        with open("/tmp/test_file", "w") as _f:
            _f.write("yes")
        assert is_done("/tmp/test_file") is True

    def test_no(self):
        with open("/tmp/test_file", "w") as _f:
            _f.write("no")
        assert is_done("/tmp/test_file") is False

זהירות

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

הפעלת הבדיקות באמצעות -v כדי להגביר את המלל מציגה את הבדיקות שעוברות:

pytest -v test_files.py
============================= test session starts ==============================
Python 3.9.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 
cachedir: .pytest_cache
rootdir: /private/
collected 2 items

test_files.py::TestIsDone::test_yes PASSED                               [ 50%]
test_files.py::TestIsDone::test_no PASSED                                [100%]

============================== 2 passed in 0.00s ===============================

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

שיטות עוזרות

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

  • setup: ביצוע פעם אחת לפני כל בדיקה בכיתה.
  • teardown: ביצוע פעם אחת לאחר כל בדיקה בכיתה.
  • setup_class: ביצוע פעם אחת לפני כל הבדיקות בכיתה.
  • teardown_class: ביצוע פעם אחת לאחר כל הבדיקות בכיתה.

כאשר בדיקות דורשות משאבים דומים (או זהים), כדאי לכתוב שיטות התקנה. מומלץ שבדיקה לא תשאיר משאבים לאחר השלמת הבדיקה, כך ששיטות ההקרעה יכולות לעזור בתיקון הבדיקות במצבים אלה.

ניקוי

בוא בחן את מחלקת הבדיקה המעודכנת ש מנקה את הקבצים לאחר כל בדיקה:

class TestIsDone:

    def teardown(self):
        if os.path.exists("/tmp/test_file"):
            os.remove("/tmp/test_file")

    def test_yes(self):
        with open("/tmp/test_file", "w") as _f:
            _f.write("yes")
        assert is_done("/tmp/test_file") is True

    def test_no(self):
        with open("/tmp/test_file", "w") as _f:
            _f.write("no")
        assert is_done("/tmp/test_file") is False

מאחר שהשתמשנו teardown() זו, מחלקת בדיקה זו אינה משאירה עוד /tmp/test_file מאחור.

ההתקנה

שיפור נוסף שאנו יכולים לבצע בכיתה זו הוא להוסיף משתנה שמצביע על הקובץ. מאחר שהקובץ מוצהר כעת ב-6 מקומות, כל שינוי בנתיב יכלול שינוי בכל הנקודות הללו. דוגמה זו מראה כיצד המחלקה נראית עם פעולת שירות setup() שמצהירה על משתנה הנתיב:

class TestIsDone:

    def setup(self):
        self.tmp_file = "/tmp/test_file"

    def teardown(self):
        if os.path.exists(self.tmp_file):
            os.remove(self.tmp_file)

    def test_yes(self):
        with open(self.tmp_file, "w") as _f:
            _f.write("yes")
        assert is_done(self.tmp_file) is True

    def test_no(self):
        with open(self.tmp_file, "w") as _f:
            _f.write("no")
        assert is_done(self.tmp_file) is False

שיטות עוזר מותאמות אישית

באפשרותך ליצור שיטות עוזר מותאמות אישית בכיתה. אין לכלול בפעולות שירות אלה קידומת עם test ולא ניתן לשנות את השם כפעולות שירות של הגדרה או ניקוי. בכיתה, TestIsDone נוכל להפוך את יצירת הקובץ הזמני לאוטומטית במסייע מותאם אישית. פעולת שירות זו של עוזר מותאם אישית עשויה להיראות כך:

    def write_tmp_file(self, content):
        with open(self.tmp_file, "w") as _f:
            _f.write(content)

Pytest אינו מבצע באופן אוטומטי write_tmp_file() זו, ושיטות אחרות יכולות לקרוא לה ישירות כדי לשמור על משימות שחוזרות על עצמן, כגון כתיבה לקובץ.

הכיתה כולה נראית כמו בדוגמה זו, לאחר עדכון שיטות הבדיקה לשימוש במסייע המותאם אישית:

class TestIsDone:

    def setup(self):
        self.tmp_file = "/tmp/test_file"

    def teardown(self):
        if os.path.exists(self.tmp_file):
            os.remove(self.tmp_file)

    def write_tmp_file(self, content):
        with open(self.tmp_file, "w") as _f:
            _f.write(content)

    def test_yes(self):
        self.write_tmp_file("yes")
        assert is_done(self.tmp_file) is True

    def test_no(self):
        self.write_tmp_file("no")
        assert is_done(self.tmp_file) is False

מתי להשתמש במחלקה במקום בפונקציה

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

  • האם הבדיקות שלך זקוקות לקוד דומה של עוזר התקנה או ניקוי?
  • האם קיבוץ הבדיקות שלך יחד הגיוני?
  • האם יש לפחות כמה בדיקות בחבילת הבדיקה שלך?
  • האם הבדיקות שלך יכולות יתרונות מערכה משותפת של פונקציות עוזרות?