۱۲/۲۱/۱۳۸۸

معرفی یک ماژول > doctest


doctest یکی از ماژولهای استاندارد پایتون است که به منظور سهولت در تست کردن کد پایتون (کپی شده از python shell) طراحی شده است. به طور کلی این ماژول برای سه منظور ممکن است استفاده شود:

  1.  بررسی به روز بودن docstring های یک ماژول با استفاده از مقایسه ی نتایج تست های ثبت شده در docstring ها با مقدار بدست آمده هنگام تست 
  2.  بررسی صحت درست کارکردن مثالهای موجود در یک فایل تست
  3. نوشتن اسناد آموزشی برای یک  package
 در این پست به شکلی ساده برخی از قابلیتهای این ماژول توضیح داده میشود. در واقع تنها به رابط اصلی و پایه ی آن (Basic API) میپردازیم.

تابع فاکتوریل را در نظر بگیرید:

def factorial(n):
    if n<0: return "Only a natural number!"
    return (1 if n==0 else n*factorial(n-1))

حالا امتحانش میکنیم:

>>> factorial(5)
120
>>> factorial(3)
6
>>> factorial(-2)
'Only a natural number!'
>>>  
میتوانیم این نتایج را به عنوان توضیحی درمورد خروجی این متود در docstring آن قرار دهیم:

def factorial(n):
    '''
    Returns factorial of a natural number
    for example:
    >>> factorial(5)
    120
    >>> factorial(3)
    6
    >>> factorial(-2)
    'Only a natural number!'
    >>>

    '''    
    if n<0: return "Only a natural number!"    
    return (1 if n==0 else n*factorial(n-1))

این نتایج به درستی محاسبه شده اند. به عبارت دیگر هرگاه این تابع به ازای مقادیری که در تست های موجود در docstring آن آمده اجرا شود همان خروجی هایی که در docstring آمده نمایان خواهند شد.
این تابع را در ماژول test.py ذخیره میکنیم.
برای اطمینان حاصل کردن از این درستی کافی است متود testmod را در انتهای ماژول test.py صدا بزنیم:

import doctest
doctest.testmod()
دوباره ماژول را اجرا میکنیم...
.
.
.
هیچ اتفاقی نمیافتد! خوب این یعنی این که نتایج موجود در تمام docstring های موجود در test.py به درستی محاسبه شده اند ☺
میتوان جزییات مربوط به این تست را این گونه دید:



حال کمی متود factorial را تغییر میدهیم تا در صورت بروز خطاهای
احتمالی در ورودی خروجی مناسبی بازگرداند:

def factorial(n):
    '''
    Returns factorial of a natural number
    for example:
    >>> factorial(5)
    120
    >>> factorial(3)
    6
    >>> factorial(-2)
    'Only a natural number!'
    >>>
    '''
    if n<0: return "Not negative integers!"
    if int(n) is not n:
        return "Must be an integer!"
    return (1 if n==0 else n*factorial(n-1))

دقت کنید doctest یک docstring را اینگونه برداشت میکند:

>>> import test #test.py contains the factorial method
>>> print doctest.testsource(test,'test.factorial')
# Returns factorial of a natural number
# for example:
factorial(5)
# Expected:
## 120
factorial(3)
# Expected:
## 6
factorial(-2)
# Expected:
## 'Only a natural number!'

>>>

دوباره ماژول را اجرا میکنیم...

>>>
**********************************************************************
File "C:\Users\SEVEN\Documents\test.py", line 9, in __main__.factorial
Failed example:
    factorial(-2)
Expected:
    'Only a natural number!'
Got:
    'Not negative integers!'
**********************************************************************
1 items had failures:
   1 of   3 in __main__.factorial
***Test Failed*** 1 failures.
>>>

نتیجه ی اخلاقی اینجا این است که هرگاه هرچیزی (مثلا یک متود) را تغییر میدهید، docstring مربوطه را نیز به روز کنید!☻
با استفاده از testmod تمام docstring های موجود در یک ماژول جستجو میشوند.(شیءهایی که import شده اند جستجو نمیشوند)

حالا میخواهیم یک فایل آموزشی درباره ی این ماژول درست کنیم. یک فایل txt با نام how_to یعنی how_to.txt میسازیم با این محتوا:

This is a tutorial documentation for test.py module

this module contains the following objects:
    factorial method

That's it for now :D

how to use factorial method:

first you have to import it like this
>>> from test import factorial

then you can use it this way:
>>> factorial(5)
120

if you enter a negative number, it can handle it:
>>> factorial(-3)
'Not negative integers!'

also if you enter a non-integer, you'll receive this message:
>>> factorial(5.5)
'Must be an integer!'

حالا میتوانیم این فایل را با استفاده از متود testfile تست کنیم:

>>> doctest.testfile("C:\Users\SEVEN\Documents\\how_to.txt")
TestResults(failed=0, attempted=4)

همانطور که دیدید testfile تمام خطوط قابل اجرا در فایل how_to را بررسی کرد و در انتها نشان داد که همگی به درستی نوشته شده بودند.

دو متود testmod و testfile ساده ترین راههای استفاده از doctest هستند. از آنجایی که این پست هم تنها قصد معرفی این ماژول را داشت بیش از این پیش نمیرویم :دی

اطلاعات بیشتر درباره ی این دو متود را اینجا خواهید یافت.
مزیت ها و اشکالات doctest نیز به طور خلاصه اینجا گردآوری شده اند.

موفق باشید ☺

۱ نظر: