یک آزمون موفّق

کمی زمان می‌برد که به روش برپایی یک مورد آزمایشی عادت کنید امّا به محض راه انداختنِ آن، افزودن آزمون‌های واحد بیشتر برای تابع‌ها سرراست خواهد بود. به منظور نوشتن یک مورد آزمایشی برای تابعی، ماژول unittest و تابعِ مورد آزمایش را وارد کنید. سپس کلاسی بسازید که از unittest.TestCase ارث می‌برد و تعدادی متد بنویسید که جنبه‌های مختلف رفتار آن تابع را می‌آزماید.

این یک مورد آزمایشی با یک متد است که بررسی می‌کند آیا تابع get_formatted_name() با دریافت یک نام و نام خانوادگی به درستی کار می‌کند یا نه:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import unittest

from name_function import get_formatted_name

class NamesTestCase(unittest.TestCase):
    """Tests for 'name_function.py'."""

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

if __name__ == '__main__':
    unittest.main()

ابتدا unittest و تابعی را که می‌خواهیم آزمایش کنیم، get_formatted_name() وارد می‌کنیم. کلاسی به نام NamesTestCase می‌سازیم که تعدادی آزمایش واحد را برای get_formatted_name() شامل می‌شود. شما می‌توانید هر نامی برای این کلاس انتخاب کنید امّا بهتر است نامی بگذارید که به تابع تحت آزمایش مربوط باشد و از واژه‌ی Test در آن استفاده کنید. کلاس باید از کلاس unittest.TestCase ارث ببرد تا پایتون بداند چگونه آزمون‌هایی را که نوشته‌اید اجرا کند.

NamesTestCase متدی دارد که یک جنبه از عملکردِ get_formatted_name() را می‌آزماید. آن را test_first_last_name() می‌نامیم زیرا در آن تنها نام‌هایی را که از نام و نام خانوادگی تشکیل شده باشند، از منظر درستیِ شکل خروجی بررسی می‌کنیم. هر متدی که با test_ شروع شده باشد، هنگام اجرای test_name_function.py به طور خودکار اجرا خواهد شد. داخل این متد آزمون، تابعی را که قرار است آزمایش شود صدا می‌کنیم. در این مثال get_formatted_name() را با نشان‌دهنده‌های 'janis' و 'joplin' صدا می‌کنیم و نتیجه‌ی آن را به formatted_name نسبت می‌دهیم.

از یکی از سودمندترین ویژگی‌های unittest بهره می‌گیریم: متد اثبات. متدهای اثبات بررسی می‌کنند که آیا نتیجه‌ای که گرفتید یا آن‌چه انتظار دارید یکی است یا نه. در این مورد چون می‌دانیم که get_formatted_name() قرار است نام کاملی با فاصله و شکلِ مناسبِ حرف‌ها برگرداند، انتظار داریم که مقدار formatted_name برابر با Janis Joplin باشد. برای آزمودن درستیِ این مورد از متد assertEqual() در unittest استفاده کرده و formatted_name و 'Janis Joplin' را به آن می‌دهیم. خطِ

1
self.assertEqual(formatted_name, 'Janis Joplin')

می‌گوید: «مقدار formatted_name را به رشته‌ی 'Janis Joplin' مقایسه کن. اگر مطابقِ انتظار، برابر بودند، همه چیز درست است. وگرنه به من اطّلاع بده.»

این فایل را به طور مستقیم اجرا می‌کنیم امّا لازم ب106 ه ذکر است که بسیاری از ابزارها یا چهارچوب‌های آزمون، فایل‌های آزمونِ شما را پیش از اجرا وارد می‌کنند. مفسّر همزمان با وارد شدنِ چنین فایلی، آن را اجرا می‌کند. بلوک if به متغّیر ویژه‌ای، __name__ نگاه می‌کند. این متغّیر هنگام اجرای برنامه تعیین می‌شود. اگر این فایل به عنوان برنامه‌ی اصلی اجرا شود، مقدار __name__ برابر با '__main__' قرار داده می‌شود. در این مورد ما unittest.main() را صدا می‌کنیم که مورد آزمایشی را اجرا می‌کند. وقتی ابزارِ آزمون این فایل را وارد می‌کند مقدار __name__ برابر با '__main__' نخواهد بود و این بلوک اجرا نمی‌شود.

وقتی test_name_function.py را اجرا می‌کنیم به این خروجی می‌رسیم:

1
2
3
4
5
6
.

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

نقطه در اوّلین خط خروجی به ما می‌گوید که آزمون موفّق بوده است. خط بعدی می‌گوید که پایتون یک آزمون را اجرا کرده و این کار کمتر از یک 0.001 ثانیه طول کشیده است. OK پایانی به ما می‌گوید که تمام آزمون‌های واحد در این مورد آزمایشی موفّق بوده‌اند.

خروجی نشان می‌دهد که تابع get_formatted_name() همیشه برای نام‌هایی که از نام و نام خانوادگی تشکیل شده‌اند کار می‌کند؛ مگر این که تابع را عوض کنیم. اگر get_formatted_name() را تغییر دهیم می‌توانیم آزمون را دوباره اجرا کنیم. اگر آزمون موفقیّت‌آمیز بود می‌فهمیم که تابع همچنان برای نام‌هایی مانند Janis Joplin کار می‌کند.