آزمودن یک کلاس
در بخش یکم این فصل آزمونهایی برای یک تابع تکّی نوشتید. اکنون آزمونهایی برای یک کلاس مینویسید. شما در برنامههای خود از کلاسها به دفعات استفاده میکنید بنابراین امکانِ ثابت کردنِ کارکردِ درستِ کلاسها سودمند است. اگر آزمونهای کلاسی که با آن کار میکنید موفّق باشد، میتوانید مطمئن باشید توسعه دادن کلاس به طور ناگهانی رفتار فعلی آن را با مشکل روبهرو نمیکند.
گسترهای از متدهای اثبات
پایتون در کلاس unittest.TestCase چند متد اثبات ارائه میکند. چنانکه پیشتر اشاره شد آزمونهای اثبات بررسی میکنند که آیا شرطی که در نقطهی خاصّی از برنامه به درستیِ آن اعتقاد دارید، واقعاً درست است یا نه. اگر شرط، مطابقِ انتظارِ شما درست باشد فرضیّهی شما در بارهی رفتار آن بخش از برنامه تایید میشود پس میتوانید مطمئن باشید که خطایی وجود ندارد. اگر شرطی که فرض میکنید درست است، نادرست باشد پایتون اعلام استثنا میکند.
جدول ۱۱-۱ شش متد اثبات متداول را شرح میدهد. با این متدها میتوانید بررسی کنید که مقدارهای بازگشتی مساوی یا مخالف مقدارهای مورد انتظار است، یا مقدارها درست یا نادرستاند، یا در یک لیست وجود دارد (in) یا نه (not in). از این متدها تنها در کلاسی میتوانید استفاده کنید که از unittest.TestCase ارث برده باشد، بنابراین اجازه دهید که در بستر آزمودن یک کلاس واقعی به نحوهی کاربرد یکی از این متدها، نگاهی بیندازیم.
| متد | کاربرد |
|---|---|
assertEqual(a, b) |
درستیسنجی a == b |
assertNotEqual(a, b) |
درستیسنجی a != b |
assertTrue(x) |
درستیسنجی این که x درست است |
assertFalse(x) |
درستیسنجی این که x نادرست است |
assertIn(item, list) |
درستیسنجی این که item در list هست یا نه |
assertNotIn(item, list) |
درستیسنجی این که item در list نیست |
کلاسی برای آزمودن
آزمودن یک کلاس مشابه آزمودن یک تابع است— بیشتر کار شما به آزمودن متدهای یک کلاس معطوف میشود. با این حال تفاوتهای کوچکی نیز وجود دارد بنابراین بیاید کلاسی برای آزمودهشدن بنویسیم. کلاسی را در نظر بگیرید که به مدیریّت نظرات ناشناس کمک میکند:
|
|
این کلاس با پرسشی که برای نظرسنجی ارائه میکنید، شروع میشود و شامل لیستی خالی برای ذخیره کردن پاسخهاست. این کلاس متدهایی برای چاپ کردن سوال نظرسنجی، افزودن پاسخ جدید به لیست پاسخها و چاپ کردن تمام پاسخهای موجود در لیست دارد. برای ساختن نمونهای از کلاس کافی است به آن پرسشی ارائه کنید. با وجود یک نمونه که بیانگر نظرسنجی خاصّی باشد، میتوانید پرسش نظرسنجی را با show_question() نشان دهید، پاسخ را به کمک store_response() ذخیره کنید و نتایج را با show_results() نمایش دهید.
برای نمایش کارکرد درست AnonymousSurvey برنامهای مینویسیم که از آن استفاده کند:
|
|
این برنامه پرسشی طرح میکند ("What language did you first learn to speak?") و یک شیء AnonymousSurvey با آن پرسش میسازد. برنامه show_question() را برای نمایش پرسش فراخوانی و سپس پاسخها را دریافت میکند. هر کدام از پاسخها به محض دریافت ذخیره میشوند. پس از وارد شدنِ تمام پرسشها (وقتی کاربر q را برای خروج وارد میکند)، متد show_results() نتایج نظرسنجی را چاپ میکند:
|
|
این کلاس برای نظرسنجیهای ناشناسِ ساده کارآمد است. امّا فرض کنید میخواهید AnonymousSurvey و ماژول دربرگیرندهی آن survey را توسعه دهیم. میتوانیم به هر کاربر اجازهی وارد کردن بیش از یک پاسخ بدهیم. میشود متدی نوشت که تنها پاسخهای یکتا را فهرست کند و گزارش کند که هر پاسخ چند بار تکرار شده است. میتوانیم کلاس دیگری برای مدیریّت نظرسنجیهای با نام بنویسیم.
پیادهسازی چنین تغییراتی این خطر را دارد که رفتار فعلی AnonymousSurvey را تحتالشعاع قرار دهد. برای مثال ممکن است حین تلاش برای دریافت چند پاسخ از یک کاربر، اشتباهاً نحوهی رسیدگی به پاسخهای تکّی را تغییر دهیم. برای این که مطمئن شویم همزمان با توسعهی این ماژول، رفتار موجود دست نمیخورد میتوانیم چند آزمون برای کلاس بنویسیم.
آزمودن کلاس AnonymousSurvey
اکنون آزمونی مینویسیم که یک جنبه از رفتار AnonymousSurvey را درستیسنجی کند. آزمونی که مینویسیم بررسی میکند که آیا پاسخِ دادهشده به پرسش نظرسنجی، به درستی ذخیره میشود یا نه. از متد assertIn() استفاده میکنیم تا پس از ذخیره کردن، وجود پاسخ را در لیستِ پاسخها بررسی کند:
|
|
از وارد کردنِ ماژول unittest و کلاس مورد آزمایش، AnonymousSurvey، شروع میکنیم. نام مورد آزمایشی را TestAnonymousSurvey میگذاریم که مجدّداً از unittest.TestCase ارث میبرد. اوّلین متد آزمایش بررسی میکند که پاسخ ارائهشده به پرسش نظرسنجی، پس از ذخیره شدن، در لیست پاسخهای نظرسنجی میآید یا نه. یک نام گویای خوب برای چنین متدی test_store_single_response() است. اگر این آزمون شکست بخورد از نام متدی که در خروجی آزمون میآید میفهمیم که مشکل در ذخیره کردن پاسخهای تکّی نظرسنجی بوده است.
برای آزمودن رفتار کلاس باید نمونهای از آن بسازیم. نمونهای به نام my_survey با پرسش "What language did you first learn to speak?" میسازیم. یک پاسخ تکّی، English، را به کمک متد store_response() ذخیره میکنیم. پس از آن با اثبات وجود English در لیست my_survey.responses، ذخیره شدن درست پاسخ را درستیسنجی میکنیم.
اجرای آزمون test_survey.py همراه با موفّقیّت خواهد بود:
این خوب است امّا نظرسنجی زمانی سودمند است که بیش از یک پاسخ تولید کند. اکنون بررسی میکنیم که آیا سه پاسخ هم به درستی ذخیره میشود یا نه. برای چنین کاری متدی دیگر به TestAnonymousSurvey اضافه میکنیم:
|
|
متد جدید test_store_three_responses() را صدا میکنیم. یک شیء نظرسنجی مانند آنچه در test_store_single_response() دیدیم ایجاد میکنیم. لیستی شامل سه پاسخ مختلف درست میکنیم، سپس برای هر کدام store_response() را فرامیخوانیم. به محض ذخیرهشدن پاسخها حلقهی دیگری مینویسیم که وجود هر پاسخ را در my_survey.responses تایید کند.
حال test_survey.py را دوباره اجرا میکنیم و هر دو آزمون (برای پاسخ تکّی و پاسخ سهتایی) قبول میشود:
این آزمون بسیار عالی کار میکند. با این حال این آزمونها کمی تکراریاند بنابراین از ویژگی دیگر unittest برای کاراتر کردن آنها استفاده میکنیم.