مقدمه

به فصل «آزمایش کدها» خوش آمدید. وقتی یک برنامه کوچک می‌نویسیم، می‌توانیم به راحتی با اجرای آن و بررسی خروجی، از صحت عملکردش مطمئن شویم. اما با بزرگتر و پیچیده‌تر شدن پروژه، این روش دستی دیگر کارآمد و قابل اعتماد نیست. «تست خودکار» (Automated Test) یک قطعه کد است که صحت عملکرد یک بخش دیگر از کد شما را به صورت خودکار بررسی می‌کند.

نوشتن تست‌ها به شما اطمینان می‌دهد که پس از افزودن یک قابلیت جدید یا بازسازی (refactor) کد، بخش‌های دیگر برنامه همچنان به درستی کار می‌کنند. این کار به شما شجاعت می‌دهد تا با خیال راحت کد خود را بهبود دهید. فریم‌ورک pytest یکی از محبوب‌ترین و قدرتمندترین ابزارها برای تست‌نویسی در پایتون است.

pytest یک پکیج خارجی است و باید آن را با استفاده از pip نصب کنیم.

$ pip install pytest
                    

نوشتن یک تست ساده

بیایید یک تابع ساده برای تست کردن بنویسیم. یک فایل به نام name_function.py ایجاد کرده و تابع زیر را در آن قرار دهید:

Copy Icon name_function.py
def get_formatted_name(first, last):
    """Generate a neatly formatted full name."""
    full_name = f"{first} {last}"
    return full_name.title()

حالا برای تست این تابع، یک فایل جدید به نام test_name_function.py ایجاد می‌کنیم. pytest به صورت خودکار تمام فایل‌هایی را که با test_ شروع یا با _test تمام می‌شوند، به عنوان فایل تست شناسایی می‌کند.

Copy Icon test_name_function.py
from name_function import get_formatted_name

def test_first_last_name():
    """Do names like 'Janis Joplin' work?"""
    formatted_name = get_formatted_name('janis', 'joplin')
    assert formatted_name == 'Janis Joplin'

در این فایل تست، ابتدا تابع مورد نظر را import می‌کنیم. سپس یک تابع تست تعریف می‌کنیم که نام آن با کلمه test_ شروع می‌شود. pytest تمام توابعی که با این پیشوند نام‌گذاری شده‌اند را به عنوان یک تست مجزا اجرا خواهد کرد.

در داخل تابع تست، ما از دستور assert استفاده می‌کنیم. این دستور یک عبارت را بررسی می‌کند و اگر نتیجه آن True باشد، تست با موفقیت پاس می‌شود. اگر نتیجه False باشد، تست شکست خورده و یک خطا نمایش داده می‌شود.

اجرای تست‌ها

برای اجرای تست‌ها، کافیست در ترمینال و در پوشه پروژه خود، دستور pytest را اجرا کنید.

$ pytest
============================= test session starts ==============================
...
collected 1 item

test_name_function.py .                                                  [100%]

============================== 1 passed in ...s ===============================
                    

خروجی نشان می‌دهد که یک تست پیدا و با موفقیت اجرا شده است (یک نقطه `.` به ازای هر تست موفق نمایش داده می‌شود).

یک تست شکست‌خورده

بیایید یک تست دیگر اضافه کنیم که انتظار داریم شکست بخورد تا ببینیم خروجی به چه شکل خواهد بود. فرض کنید می‌خواهیم نام‌های سه‌قسمتی را نیز پشتیبانی کنیم.

Copy Icon test_name_function.py
def test_first_last_middle_name():
    """Do names like 'Wolfgang Amadeus Mozart' work?"""
    formatted_name = get_formatted_name('wolfgang', 'mozart', 'amadeus')
    assert formatted_name == 'Wolfgang Amadeus Mozart'

اگر دوباره pytest را اجرا کنیم، خواهیم دید که یک تست پاس شده و یک تست شکست می‌خورد. pytest یک خروجی دقیق از علت شکست تست ارائه می‌دهد که به ما در دیباگ کردن کمک می‌کند.

در این درس با اصول اولیه تست‌نویسی با استفاده از فریم‌ورک قدرتمند pytest آشنا شدیم. دیدیم که چگونه می‌توان با نوشتن توابع تست و استفاده از دستور assert، صحت عملکرد توابع خود را به صورت خودکار بررسی کنیم. در درس بعدی، به سراغ «تست یک کلاس با استفاده از pytest» خواهیم رفت و یاد می‌گیریم که چگونه برای کلاس‌ها و متدهای آنها تست بنویسیم.