unittest --- چارچوب آزمون واحد¶
کد منبع: Lib/unittest/__init__.py
(اگر از پیش با مفاهیم پایهای آزمون آشنا هستید، شاید بخواهید به فهرست متدهای assert بروید.)
چارچوب آزمون واحد unittest در اصل از JUnit الهام گرفته شده است و سبکی مشابه چارچوبهای اصلی آزمون واحد در سایر زبانها دارد. این چارچوب از خودکارسازی آزمون، به اشتراکگذاری کد راهاندازی و خاموشسازی برای آزمونها، تجمیع آزمونها در مجموعهها، و استقلال آزمونها از چارچوب گزارشدهی پشتیبانی میکند.
برای دستیابی به این هدف، unittest از برخی مفاهیم مهم بهصورت شیءگرا پشتیبانی میکند:
- تدارکات آزمون (test fixture)
یک تدارک آزمون <test fixture> نشاندهندهی آمادهسازی لازم برای اجرای یک یا چند آزمون و هرگونه اقدام پاکسازی مرتبط است. این ممکن است برای مثال شامل ایجاد پایگاههای دادهی موقت یا پراکسی، پوشهها، یا راهاندازی یک فرایند سرور باشد.
- مورد آزمون
یک مورد آزمون <test case> واحد منفرد آزمون است. این مورد، پاسخ مشخصی به یک مجموعهی معین از ورودیها را بررسی میکند.
unittestکلاس پایهای،TestCase، را فراهم میکند که میتوان از آن برای ایجاد موارد آزمون جدید استفاده کرد.- بدنه آزمون
یک بدنه آزمون <test suite> مجموعهای از موارد آزمون، بدنههای آزمون، یا هر دو است. این برای تجمیع آزمونهایی که باید با هم اجرا شوند استفاده میشود.
- اجراکننده آزمون
یک اجراکننده آزمون <test runner> کامپوننتی است که اجرای آزمونها را هماهنگ میکند و نتیجه را در اختیار کاربر قرار میدهد. این اجراکننده ممکن است از یک رابط گرافیکی، یک رابط متنی استفاده کند یا مقدار خاصی را برای نشان دادن نتایج اجرای آزمونها برگرداند.
همچنین ملاحظه نمائید
- ماژول
doctest ماژول پشتیبانی آزمون دیگری با حالوهوای بسیار متفاوت.
- آزمون ساده Smalltalk: با الگوها <https://web.archive.org/web/20150315073817/http://www.xprogramming.com/testfram.htm>_
مقالهی اصلی کنت بک دربارهی چارچوبهای آزمون که از الگوی مشترک با
unittestاستفاده میکنند.- pytest
چارچوب آزمون واحد شخص ثالث با سینتکس سبکتر برای نوشتن آزمونها. برای مثال،
assert func(10) == 42.- ردهبندی ابزارهای آزمون پایتون
فهرست جامعی از ابزارهای آزمون پایتون، شامل چارچوبهای آزمون عملکردی و کتابخانههای اشیای ماک.
- فهرست پستی Testing in Python
یک گروه ویژه علاقهمندان (special-interest-group) برای بحث دربارهی آزمون و ابزارهای آزمون در پایتون.
اسکریپت Tools/unittestgui/unittestgui.py در توزیع کد منبع پایتون، یک ابزار GUI برای کشف و اجرای آزمون است. این ابزار عمدتاً برای سهولت استفادهی تازهکاران آزمون واحد در نظر گرفته شده است. برای محیطهای تولید، توصیه میشود که آزمونها توسط یک سیستم یکپارچهسازی مداوم مانند Buildbot، Jenkins، GitHub Actions یا AppVeyor اجرا شوند.
مثال ساده¶
ماژول unittest مجموعهای غنی از ابزارها را برای ساخت و اجرای آزمونها فراهم میکند. این بخش نشان میدهد که زیرمجموعهای کوچک از ابزارها برای برآوردن نیازهای بیشتر کاربران کافی است.
در اینجا یک اسکریپت کوتاه برای آزمایش سه متد رشته آمده است:
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
یک مورد آزمون با ایجاد یک زیرکلاس از unittest.TestCase ساخته میشود. سه آزمون مجزا با متدهایی تعریف میشوند که نام آنها با نویسههای test آغاز میشود. این قرارداد نامگذاری به اجراکننده آزمون اطلاع میدهد که کدام متدها نشاندهنده آزمونها هستند.
اصل هر آزمون، فراخوانی assertEqual() برای بررسی نتیجهی مورد انتظار؛ فراخوانی assertTrue() یا assertFalse() برای تأیید یک شرط؛ یا فراخوانی assertRaises() برای تأیید پرتاب یک استثنای خاص است. این متدها بهجای دستور assert استفاده میشوند تا اجراکنندهی آزمون (test runner) بتواند همهی نتایج آزمون را جمعآوری کند و گزارشی تولید کند.
متدهای setUp() و tearDown() به شما امکان میدهند دستوراتی را تعریف کنید که پیش و پس از هر متد آزمون اجرا میشوند. این موارد با جزئیات بیشتر در بخش سازماندهی کد آزمون پوشش داده شدهاند.
بلوک نهایی یک راه ساده برای اجرای آزمونها نشان میدهد. unittest.main() یک رابط خط فرمان برای اسکریپت آزمون فراهم میکند. هنگام اجرا از خط فرمان، اسکریپت بالا خروجیای شبیه به این تولید میکند:
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
دادن گزینه -v به اسکریپت آزمون شما، باعث میشود unittest.main() سطح بالاتری از جزئیات را فعال کند و خروجی زیر را تولید کند:
test_isupper (__main__.TestStringMethods.test_isupper) ... ok
test_split (__main__.TestStringMethods.test_split) ... ok
test_upper (__main__.TestStringMethods.test_upper) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK
مثالهای بالا رایجترین قابلیتهای unittest را نشان میدهند که برای برآورده کردن بسیاری از نیازهای روزمرهی آزمون کافی هستند. باقیماندهی مستندات مجموعهی کامل قابلیتها را از اصول اولیه بررسی میکند.
تغییر یافته در نسخهی 3.11: رفتار برگرداندن مقدار از یک متد آزمون (غیر از مقدار پیشفرض None)، اکنون منسوخ شده است.
رابط خط فرمان¶
میتوان از ماژول unittest از خط فرمان برای اجرای آزمونها از ماژولها، کلاسها یا حتی متدهای آزمون منفرد استفاده کرد:
python -m unittest test_module1 test_module2
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method
میتوانید فهرستی شامل هر ترکیبی از نام ماژولها و نامهای کامل کلاس یا متد را وارد کنید.
همچنین میتوان ماژولهای آزمون را با مسیر پرونده مشخص کرد:
python -m unittest tests/test_something.py
این امکان را به شما میدهد که از قابلیت تکمیل نام پرونده پوسته برای مشخص کردن ماژول آزمون استفاده کنید. پرونده مشخصشده همچنان باید بهعنوان یک ماژول قابل ایمپورت باشد. مسیر با حذف '.py' و تبدیل جداکنندههای مسیر به '.' به نام ماژول تبدیل میشود. اگر میخواهید یک پرونده آزمون را اجرا کنید که بهعنوان یک ماژول قابل ایمپورت نیست، باید در عوض پرونده را مستقیماً اجرا کنید.
میتوانید با افزودن پرچم -v، آزمونها را با جزئیات بیشتر (سطح جزئیات بالاتر) اجرا کنید:
python -m unittest -v test_module
هنگامی که بدون آرگومان اجرا شود، کشف آزمون آغاز میشود:
python -m unittest
برای فهرستی از تمام گزینههای خط فرمان:
python -m unittest -h
تغییر یافته در نسخهی 3.2: در نسخههای پیشین، تنها میتوانستید متدهای آزمون را بهصورت جداگانه اجرا کنید، نه ماژولها یا کلاسها را.
اضافه شده در نسخهی 3.14: خروجی بهطور پیشفرض رنگی است و میتواند با استفاده از متغیرهای محیطی کنترل شود.
گزینههای خط فرمان¶
unittest از این گزینههای خط فرمان پشتیبانی میکند:
- -b, --buffer¶
جریانهای خروجی استاندارد و خطای استاندارد در طول اجرای آزمون، در بافر ذخیره میشوند. خروجی در طول یک آزمون موفق دور ریخته میشود. خروجی بهطور عادی در صورت شکست یا خطای آزمون بازتاب داده میشود و به پیامهای شکست اضافه میشود.
- -c, --catch¶
Control-C در حین اجرای آزمون منتظر میماند تا آزمون جاری به پایان برسد و سپس همه نتایج تاکنون را گزارش میکند. دومین Control-C استثنای معمول
KeyboardInterruptرا پرتاب میکند.برای آشنایی با توابعی که این قابلیت را فراهم میکنند، به Signal Handling مراجعه کنید.
- -f, --failfast¶
در اولین خطا یا شکست، اجرای آزمون را متوقف کنید.
- -k¶
فقط متدها و کلاسهای آزمونی را اجرا میکند که با الگو یا زیررشته مطابقت دارند. این گزینه را میتوان چندین بار استفاده کرد، که در این صورت تمام موارد آزمونی که با هر یک از الگوهای دادهشده مطابقت داشته باشند، گنجانده میشوند.
الگوهایی که شامل یک وایلدکارد (
*) هستند، با استفاده ازfnmatch.fnmatchcase()با نام آزمون تطبیق داده میشوند؛ در غیر این صورت، از تطبیق سادهی زیررشته با حساسیت به بزرگی و کوچکی حروف استفاده میشود.الگوها با نام کامل متد آزمون، به همان شکلی که توسط بارگذار آزمون ایمپورت شده است، تطبیق داده میشوند.
برای مثال،
-k fooباfoo_tests.SomeTest.test_somethingوbar_tests.SomeTest.test_fooمطابقت دارد، اما باbar_tests.FooTest.test_somethingمطابقت ندارد.
- --locals¶
نمایش متغیرهای محلی در ردگیریهای پشته.
- --durations N¶
نمایش N مورد از کندترین موارد آزمون (N=0 برای همه).
اضافه شده در نسخهی 3.2: گزینههای خط فرمان -b، -c و -f افزوده شدند.
اضافه شده در نسخهی 3.5: گزینهی خط فرمان --locals.
اضافه شده در نسخهی 3.7: گزینهی خط فرمان -k.
اضافه شده در نسخهی 3.12: گزینهی خط فرمان --durations.
همچنین میتوان از خط فرمان برای کشف آزمون، برای اجرای همهی آزمونهای یک پروژه یا فقط زیرمجموعهای از آنها استفاده کرد.
کشف آزمون¶
اضافه شده در نسخهی 3.2.
Unittest از کشف سادهی آزمون پشتیبانی میکند. برای سازگاری با کشف آزمون، همهی پروندههای آزمون باید ماژولها یا بستههایی باشند که بتوان آنها را از پوشهی سطح بالای پروژه ایمپورت کرد (این بدان معناست که نام پروندههای آنها باید شناسههای معتبر باشد).
کشف آزمون (test discovery) در TestLoader.discover() پیادهسازی شده است، اما میتوان از آن در خط فرمان نیز استفاده کرد. استفادهی پایه در خط فرمان به این صورت است:
cd project_directory
python -m unittest discover
توجه
بهعنوان میانبر، python -m unittest معادل python -m unittest discover است. اگر میخواهید آرگومانهایی را به کشف آزمون بدهید، باید بهصراحت از زیردستور discover استفاده شود.
زیردستور discover گزینههای زیر را دارد:
- -v, --verbose¶
خروجی پرجزئیات
- -s, --start-directory directory¶
پوشه برای آغاز کشف (پیشفرض
.)
- -p, --pattern pattern¶
الگو برای تطبیق پروندههای آزمون (پیشفرض:
test*.py)
- -t, --top-level-directory directory¶
پوشهی سطح بالای پروژه (بهطور پیشفرض پوشهی شروع)
میتوان گزینههای -s، -p و -t را بهترتیب بهعنوان آرگومانهای جایگاهی ارسال کرد. دو خط فرمان زیر معادل هستند:
python -m unittest discover -s project_directory -p "*_test.py"
python -m unittest discover project_directory "*_test.py"
علاوه بر مسیر، میتوانید یک نام بسته را نیز بهعنوان پوشه شروع ارسال کنید؛ برای مثال myproject.subpackage.test. نام بستهای که ارائه میدهید سپس ایمپورت میشود و محل آن در سامانه فایلبندی بهعنوان پوشه شروع استفاده خواهد شد.
ملاحظه
کشف آزمون، آزمونها را با ایمپورت کردن آنها بارگذاری میکند. هنگامی که کشف آزمون همهی پروندههای آزمون را از پوشهی شروعی که مشخص میکنید پیدا کرد، مسیرها را به نامهای بسته برای ایمپورت تبدیل میکند. برای مثال foo/bar/baz.py بهصورت foo.bar.baz ایمپورت میشود.
اگر بستهای بهصورت سراسری نصب شده باشد و تلاش کنید کشف آزمون را روی کپی دیگری از آن بسته انجام دهید، آنگاه ایمپورت میتواند از مکان اشتباهی انجام شود. اگر این اتفاق بیفتد، کشف آزمون به شما هشدار میدهد و خارج میشود.
اگر پوشه شروع را بهعنوان نام بسته ارائه دهید، نه بهعنوان مسیر یک پوشه، discover فرض میکند هر مکانی که از آن ایمپورت میکند همان مکان مورد نظر شماست، بنابراین هشدار را دریافت نخواهید کرد.
ماژولها و بستههای آزمون میتوانند بارگذاری و کشف آزمونها را از طریق load_tests protocol سفارشیسازی کنند.
تغییر یافته در نسخهی 3.4: کشف آزمون از بستههای فضای نام پشتیبانی میکند.
تغییر یافته در نسخهی 3.11: کشف آزمون، پشتیبانی از بستههای فضای نام را حذف کرد. این قابلیت از پایتون 3.7 خراب بوده است. پوشه شروع و زیرپوشههای آن که حاوی آزمونها هستند، باید بستههای معمولی باشند که پرونده __init__.py دارند.
اگر پوشه شروع، نام نقطهدار بسته باشد، بستههای اجدادی میتوانند بستههای فضای نامی باشند.
تغییر یافته در نسخهی 3.14: کشف آزمون دوباره از بسته فضای نام بهعنوان پوشه شروع پشتیبانی میکند. برای اجتناب از پویش پوشههای نامرتبط با پایتون، آزمونها در زیرپوشههایی که حاوی __init__.py نیستند، جستجو نمیشوند.
سازماندهی کد آزمون¶
اجزای سازندهی اساسی آزمون واحد، موارد آزمون <test cases> هستند --- سناریوهای منفردی که باید راهاندازی و از نظر صحت بررسی شوند. در unittest، موارد آزمون با نمونههای unittest.TestCase نمایش داده میشوند. برای ساخت موارد آزمون خودتان، باید زیرکلاسهایی از TestCase بنویسید یا از FunctionTestCase استفاده کنید.
کد آزمون یک نمونه TestCase باید کاملاً مستقل باشد، بهطوری که بتوان آن را بهتنهایی یا در ترکیب دلخواه با هر تعداد از موردهای آزمون دیگر اجرا کرد.
سادهترین زیرکلاس TestCase صرفاً یک متد آزمون (یعنی متدی که نام آن با test شروع میشود) را برای اجرای کد آزمون خاص پیادهسازی میکند:
import unittest
class DefaultWidgetSizeTestCase(unittest.TestCase):
def test_default_widget_size(self):
widget = Widget('The widget')
self.assertEqual(widget.size(), (50, 50))
توجه داشته باشید که برای آزمایش یک مورد، از یکی از متدهای assert* ارائهشده توسط کلاس پایهی TestCase استفاده میکنیم. اگر آزمایش شکست بخورد، یک استثنا همراه با پیام توضیحی پرتاب خواهد شد و unittest مورد آزمایشی را بهعنوان شکست <failure> شناسایی خواهد کرد. سایر استثناها بهعنوان خطاها <errors> در نظر گرفته خواهند شد.
آزمونها میتوانند متعدد باشند و راهاندازی آنها میتواند تکراری باشد. خوشبختانه، میتوانیم کد راهاندازی را با پیادهسازی متدی به نام setUp() جدا کنیم، که چارچوب آزمون آن را برای تکتک آزمونهایی که اجرا میکنیم بهطور خودکار فراخوانی میکند:
import unittest
class WidgetTestCase(unittest.TestCase):
def setUp(self):
self.widget = Widget('The widget')
def test_default_widget_size(self):
self.assertEqual(self.widget.size(), (50,50),
'incorrect default size')
def test_widget_resize(self):
self.widget.resize(100,150)
self.assertEqual(self.widget.size(), (100,150),
'wrong size after resize')
توجه
ترتیب اجرای آزمونهای مختلف با مرتبسازی نام متدهای آزمون بر اساس ترتیب توکار برای رشتهها تعیین میشود.
اگر متد setUp() در حین اجرای آزمون استثنایی را پرتاب کند، چارچوب در نظر خواهد گرفت که آزمون دچار خطا شده است و متد آزمون اجرا نخواهد شد.
بهطور مشابه، میتوانیم یک متد tearDown() فراهم کنیم که پس از اجرای متد آزمون، پاکسازی میکند:
import unittest
class WidgetTestCase(unittest.TestCase):
def setUp(self):
self.widget = Widget('The widget')
def tearDown(self):
self.widget.dispose()
اگر setUp() با موفقیت انجام شده باشد، tearDown() اجرا خواهد شد، چه متد آزمون موفق شده باشد چه نه.
به چنین محیط کاری برای کد آزمون، ثابت آزمایشی آزمون <test fixture> گفته میشود. یک نمونه جدید از TestCase بهعنوان یک ثابت آزمایشی آزمون یکتا برای اجرای هر متد آزمون بهطور جداگانه ایجاد میشود. بنابراین setUp()، tearDown() و TestCase.__init__() یک بار به ازای هر آزمون فراخوانی خواهند شد.
توصیه میشود از پیادهسازیهای TestCase برای گروهبندی آزمونها بر اساس قابلیتهایی که مورد آزمون قرار میدهند استفاده کنید. unittest سازوکاری برای این منظور فراهم میکند: بدنهی آزمون <test suite>، که توسط کلاس TestSuite از unittest نمایش داده میشود. در بیشتر موارد، فراخوانی unittest.main() کار درست را انجام میدهد و تمام موارد آزمون ماژول را برای شما جمعآوری و اجرا میکند.
با این حال، اگر بخواهید ساخت بدنهی آزمون خود را سفارشیسازی کنید، میتوانید خودتان این کار را انجام دهید:
def suite():
suite = unittest.TestSuite()
suite.addTest(WidgetTestCase('test_default_widget_size'))
suite.addTest(WidgetTestCase('test_widget_resize'))
return suite
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(suite())
میتوانید تعاریف موارد آزمون و مجموعههای آزمون را در همان ماژولهایی قرار دهید که کد مورد آزمون در آنها قرار دارد (مانند widget.py)، اما قرار دادن کد آزمون در یک ماژول جداگانه چندین مزیت دارد، مانند test_widget.py:
ماژول آزمون را میتوان بهصورت مستقل از خط فرمان اجرا کرد.
کد آزمون را میتوان بهآسانی بیشتری از کد تحویلشده جدا کرد.
وسوسه کمتری وجود دارد که بدون دلیل موجه، کد آزمون را تغییر دهید تا با کد مورد آزمون تطبیق یابد.
کد آزمون باید بسیار کمتر از کدی که آن را آزمون میکند، تغییر کند.
کد آزمونشده بهآسانی بیشتری قابل بازساخت است.
به هر حال، آزمونهای ماژولهای نوشتهشده با C باید در ماژولهای جداگانه باشند، پس چرا یکدست نباشیم؟
اگر راهبرد آزمون تغییر کند، نیازی به تغییر کد منبع نیست.
استفاده مجدد از کد آزمون قدیمی¶
برخی کاربران متوجه خواهند شد که کد آزمون موجودی دارند که میخواهند آن را از unittest اجرا کنند، بدون اینکه هر تابع آزمون قدیمی را به یک زیرکلاس TestCase تبدیل کنند.
به همین دلیل، unittest یک کلاس FunctionTestCase را فراهم میکند. میتوان از این زیرکلاسِ TestCase برای دربرگرفتن یک تابع آزمون موجود استفاده کرد. همچنین میتوان توابع راهاندازی و پاکسازی را نیز ارائه کرد.
با توجه به تابع آزمون زیر:
def testSomething():
something = makeSomething()
assert something.name is not None
# ...
میتوانید یک نمونه معادل از مورد آزمون را به صورت زیر ایجاد کنید، با متدهای اختیاری راهاندازی و پاکسازی:
testcase = unittest.FunctionTestCase(testSomething,
setUp=makeSomethingDB,
tearDown=deleteSomethingDB)
توجه
اگرچه میتوان از FunctionTestCase برای تبدیل سریع یک پایهی آزمون موجود به سامانهای مبتنی بر unittest استفاده کرد، این روش توصیه نمیشود. صرف زمان برای ایجاد زیرکلاسهای مناسب TestCase، بازآراییهای آیندهی آزمونها را بینهایت آسانتر خواهد کرد.
در برخی موارد، ممکن است آزمونهای موجود با استفاده از ماژول doctest نوشته شده باشند. در این صورت، doctest کلاس DocTestSuite را فراهم میکند که میتواند بهصورت خودکار نمونههای unittest.TestSuite را از آزمونهای موجود مبتنی بر doctest بسازد.
پرش از آزمونها و شکستهای مورد انتظار¶
اضافه شده در نسخهی 3.1.
آزمون واحد از پرش از متدهای آزمون جداگانه و حتی کلاسهای کاملی از آزمونها پشتیبانی میکند. علاوه بر این، از علامتگذاری یک آزمون بهعنوان «شکست مورد انتظار» پشتیبانی میکند؛ آزمونی که خراب است و شکست خواهد خورد، اما نباید بهعنوان یک شکست در یک TestResult محسوب شود.
رد کردن یک آزمون بهسادگی با استفاده از دکوراتور @skip یا یکی از گونههای شرطی آن، فراخوانی TestCase.skipTest() در متد setUp() یا متد آزمون، یا پرتاب مستقیم SkipTest انجام میشود.
پرش ساده به این شکل است:
class MyTestCase(unittest.TestCase):
@unittest.skip("demonstrating skipping")
def test_nothing(self):
self.fail("shouldn't happen")
@unittest.skipIf(mylib.__version__ < (1, 3),
"not supported in this library version")
def test_format(self):
# Tests that work for only a certain version of the library.
pass
@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
def test_windows_support(self):
# windows specific testing code
pass
def test_maybe_skipped(self):
if not external_resource_available():
self.skipTest("external resource not available")
# test code that depends on the external resource
pass
این خروجی اجرای مثال بالا در حالت پرجزئیات است:
test_format (__main__.MyTestCase.test_format) ... skipped 'not supported in this library version'
test_nothing (__main__.MyTestCase.test_nothing) ... skipped 'demonstrating skipping'
test_maybe_skipped (__main__.MyTestCase.test_maybe_skipped) ... skipped 'external resource not available'
test_windows_support (__main__.MyTestCase.test_windows_support) ... skipped 'requires Windows'
----------------------------------------------------------------------
Ran 4 tests in 0.005s
OK (skipped=4)
میتوان از کلاسها درست مانند متدها پرش کرد:
@unittest.skip("showing class skipping")
class MySkippedTestCase(unittest.TestCase):
def test_not_run(self):
pass
TestCase.setUp() همچنین میتواند آزمون را رد کند. این زمانی مفید است که منبعی که باید راهاندازی شود، در دسترس نیست.
برای شکستهای مورد انتظار از دکوراتور @expectedFailure استفاده میشود.
class ExpectedFailureTestCase(unittest.TestCase):
@unittest.expectedFailure
def test_fail(self):
self.assertEqual(1, 0, "broken")
با ساختن دکوراتوری که هر زمان بخواهد آزمونی رد شود، skip() را روی آن آزمون فراخوانی میکند، میتوانید بهآسانی دکوراتورهای سفارشی خودتان را برای رد کردن آزمون بسازید. این دکوراتور، آزمون را رد میکند، مگر آنکه شیء دادهشده دارای ویژگی مشخصی باشد:
def skipUnlessHasattr(obj, attr):
if hasattr(obj, attr):
return lambda func: func
return unittest.skip("{!r} doesn't have {!r}".format(obj, attr))
دکوراتورها و استثنای زیر، پرش از آزمون و شکستهای مورد انتظار را پیادهسازی میکنند:
- @unittest.skip(reason)¶
بدون قید و شرط از آزمون دکوریتشده پرش میکند. reason باید دلیل پرش از آزمون را توضیح دهد.
- @unittest.skipIf(condition, reason)¶
اگر condition درست باشد، از آزمون دکوریتشده صرفنظر میشود.
- @unittest.skipUnless(condition, reason)¶
آزمون دکوریتشده را رد میکند، مگر اینکه condition درست باشد.
- @unittest.expectedFailure¶
آزمون را بهعنوان شکست یا خطای مورد انتظار علامتگذاری میکند. اگر آزمون در خود تابع آزمون با شکست یا خطا مواجه شود (نه در یکی از متدهای test fixture)، موفقیت در نظر گرفته میشود. اگر آزمون با موفقیت اجرا شود، شکست در نظر گرفته میشود.
- exception unittest.SkipTest(reason)¶
این استثنا برای پرش از یک آزمون پرتاب میشود.
معمولاً میتوانید بهجای اینکه این را مستقیماً پرتاب کنید، از
TestCase.skipTest()یا یکی از دکوراتورهای پرش استفاده کنید.
برای آزمونهای ردشده، setUp() یا tearDown() پیش و پس از آنها اجرا نخواهد شد. برای کلاسهای ردشده، setUpClass() یا tearDownClass() اجرا نخواهد شد. برای ماژولهای ردشده، setUpModule() یا tearDownModule() اجرا نخواهد شد.
تمایز تکرارهای آزمون با استفاده از زیرآزمونها¶
اضافه شده در نسخهی 3.4.
هنگامی که تفاوتهای بسیار کوچکی میان آزمونهای شما وجود دارد، برای مثال برخی پارامترها، unittest به شما امکان میدهد آنها را در بدنهی یک متد آزمون با استفاده از مدیر زمینهی subTest() از هم متمایز کنید.
برای مثال، آزمون زیر:
class NumbersTest(unittest.TestCase):
def test_even(self):
"""
Test that numbers between 0 and 5 are all even.
"""
for i in range(0, 6):
with self.subTest(i=i):
self.assertEqual(i % 2, 0)
خروجی زیر را تولید خواهد کرد:
FAIL: test_even (__main__.NumbersTest.test_even) (i=1)
Test that numbers between 0 and 5 are all even.
----------------------------------------------------------------------
Traceback (most recent call last):
File "subtests.py", line 11, in test_even
self.assertEqual(i % 2, 0)
^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 1 != 0
======================================================================
FAIL: test_even (__main__.NumbersTest.test_even) (i=3)
Test that numbers between 0 and 5 are all even.
----------------------------------------------------------------------
Traceback (most recent call last):
File "subtests.py", line 11, in test_even
self.assertEqual(i % 2, 0)
^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 1 != 0
======================================================================
FAIL: test_even (__main__.NumbersTest.test_even) (i=5)
Test that numbers between 0 and 5 are all even.
----------------------------------------------------------------------
Traceback (most recent call last):
File "subtests.py", line 11, in test_even
self.assertEqual(i % 2, 0)
^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 1 != 0
بدون استفاده از یک زیرآزمون (subtest)، اجرا پس از اولین شکست متوقف میشد و تشخیص خطا دشوارتر بود، زیرا مقدار i نمایش داده نمیشد:
FAIL: test_even (__main__.NumbersTest.test_even)
----------------------------------------------------------------------
Traceback (most recent call last):
File "subtests.py", line 32, in test_even
self.assertEqual(i % 2, 0)
AssertionError: 1 != 0
کلاسها و توابع¶
این بخش API مربوط به unittest را بهطور عمیق شرح میدهد.
موارد آزمون¶
- class unittest.TestCase(methodName='runTest')¶
نمونههای کلاس
TestCaseنشاندهندهی واحدهای منطقی آزمون در جهانunittestهستند. این کلاس برای استفاده بهعنوان یک کلاس پایه در نظر گرفته شده است، بهطوری که آزمونهای خاص توسط زیرکلاسهای عینی پیادهسازی شوند. این کلاس رابط مورد نیاز اجراکننده آزمون را پیادهسازی میکند تا اجراکننده بتواند آزمونها را راهبری کند، و نیز متدهایی را پیادهسازی میکند که کد آزمون میتواند برای بررسی و گزارش انواع مختلف شکست از آنها استفاده کند.هر نمونه از
TestCaseیک متد پایه واحد را اجرا میکند: متدی که methodName نام دارد. در بیشتر موارد استفاده ازTestCase، شما نه methodName را تغییر میدهید و نه متد پیشفرضrunTest()را مجدداً پیادهسازی میکنید.تغییر یافته در نسخهی 3.2:
TestCaseرا میتوان بدون ارائهی methodName با موفقیت نمونهسازی کرد. این کار آزمایش باTestCaseاز مفسر تعاملی را آسانتر میکند.نمونههای
TestCaseسه گروه از متدها را ارائه میدهند: یک گروه برای اجرای آزمون، گروه دیگر که توسط پیادهسازی آزمون برای بررسی شرایط و گزارش شکستها استفاده میشود، و چند متد پرسوجو که امکان جمعآوری اطلاعات درباره خود آزمون را فراهم میکنند.متدهای گروه اول (اجرای آزمون) عبارتند از:
- setUp()¶
متدی که برای آمادهسازی ثابت آزمایشی فراخوانی میشود. این متد بلافاصله پیش از فراخوانی متد آزمون فراخوانی میشود؛ بهجز
AssertionErrorیاSkipTest، هر استثنایی که توسط این متد پرتاب شود، بهعنوان خطا در نظر گرفته خواهد شد، نه شکست آزمون. پیادهسازی پیشفرض هیچ کاری انجام نمیدهد.
- tearDown()¶
متدی که بلافاصله پس از فراخوانی متد آزمون و ثبت نتیجه فراخوانی میشود. این متد حتی اگر متد آزمون استثنایی را پرتاب کرده باشد نیز فراخوانی میشود، بنابراین پیادهسازی در زیرکلاسها ممکن است نیازمند دقت ویژهای در بررسی وضعیت داخلی باشد. هر استثنایی غیر از
AssertionErrorیاSkipTestکه توسط این متد پرتاب شود، بهعنوان یک خطای اضافی در نظر گرفته میشود، نه شکست آزمون (بنابراین تعداد کل خطاهای گزارششده را افزایش میدهد). این متد تنها در صورتی فراخوانی میشود کهsetUp()با موفقیت اجرا شود، صرفنظر از نتیجه متد آزمون. پیادهسازی پیشفرض هیچ کاری انجام نمیدهد.
- setUpClass()¶
یک متد کلاس که پیش از اجرای آزمونهای یک کلاس منفرد فراخوانی میشود.
setUpClassبا کلاس بهعنوان تنها آرگومان فراخوانی میشود و باید با دکوراتور@classmethodآراسته شود:@classmethod def setUpClass(cls): ...
برای جزئیات بیشتر Class and Module Fixtures را ببینید.
اضافه شده در نسخهی 3.2.
- tearDownClass()¶
یک متد کلاس که پس از اجرای آزمونها در یک کلاس منفرد فراخوانی میشود.
tearDownClassبا کلاس بهعنوان تنها آرگومان فراخوانی میشود و باید با دکوراتور@classmethodآراسته شود:@classmethod def tearDownClass(cls): ...
برای جزئیات بیشتر Class and Module Fixtures را ببینید.
اضافه شده در نسخهی 3.2.
- run(result=None)¶
آزمون را اجرا میکند و نتیجه را در شیء
TestResultکه بهعنوان result ارسالشده است، جمعآوری میکند. اگر result حذفشده باشد یاNoneباشد، یک شیء نتیجهی موقت ایجاد میشود (با فراخوانی متدdefaultTestResult()) و مورد استفاده قرار میگیرد. شیء نتیجه به فراخوانندهیrun()برگردانده میشود.میتوان همان اثر را بهسادگی با فراخوانی نمونهی
TestCaseبه دست آورد.تغییر یافته در نسخهی 3.3: نسخههای پیشین
runنتیجه را برنمیگرداندند. فراخوانی یک نمونه نیز همینطور بود.
- skipTest(reason)¶
فراخوانی این در حین اجرای یک متد آزمون یا
setUp()، آزمون فعلی را رد میکند. برای اطلاعات بیشتر پرش از آزمونها و شکستهای مورد انتظار را ببینید.اضافه شده در نسخهی 3.1.
- subTest(msg=None, **params)¶
یک مدیر زمینه برمیگرداند که بلوک کد محصورشده را بهعنوان یک زیرآزمون (subtest) اجرا میکند. msg و params مقادیر اختیاری و دلخواهی هستند که هر زمان یک زیرآزمون شکست بخورد، نمایش داده میشوند تا بتوانید آنها را بهوضوح شناسایی کنید.
یک مورد آزمون (test case) میتواند شامل هر تعداد اعلامیهی زیرآزمون (subtest) باشد و این اعلامیهها میتوانند بهصورت دلخواه تودرتو شوند.
برای اطلاعات بیشتر تمایز تکرارهای آزمون با استفاده از زیرآزمونها را ببینید.
اضافه شده در نسخهی 3.4.
- debug()¶
آزمون را بدون جمعآوری نتیجه اجرا کنید. این کار اجازه میدهد استثناهای پرتابشده توسط آزمون به فراخواننده منتشر شوند و میتواند برای پشتیبانی از اجرای آزمونها تحت اشکالزدا استفاده شود.
کلاس
TestCaseچندین متد assert برای بررسی و گزارش شکستها فراهم میکند. جدول زیر رایجترین متدها را فهرست میکند (برای متدهای assert بیشتر، جدولهای زیر را ببینید):متد
بررسی میکند که
جدید در
a == ba != bbool(x) is Truebool(x) is Falsea is b3.1
a is not b3.1
x is None3.1
x is not None3.1
a in b3.1
a not in b3.1
isinstance(a, b)3.2
not isinstance(a, b)3.2
issubclass(a, b)3.14
not issubclass(a, b)3.14
همهی متدهای assert یک آرگومان msg میپذیرند که در صورت تعیین شدن، بهعنوان پیام خطا هنگام شکست استفاده میشود (همچنین
longMessageرا ببینید). توجه داشته باشید که آرگومان کلیدواژهای msg فقط زمانی میتواند بهassertRaises()،assertRaisesRegex()،assertWarns()وassertWarnsRegex()ارسال شود که این متدها بهعنوان مدیر زمینه استفاده شوند.- assertEqual(first, second, msg=None)¶
آزمون میکند که first و second برابر باشند. اگر مقادیر در مقایسه برابر نباشند، آزمون شکست میخورد.
علاوه بر این، اگر first و second دقیقاً نوع یکسانی باشند و آن نوع یکی از list، tuple، dict، set، frozenset یا str یا هر نوعی باشد که یک زیرکلاس آن را با
addTypeEqualityFunc()ثبت کند، تابع برابری مختص نوع فراخوانی میشود تا پیام خطای پیشفرض مفیدتری تولید کند (همچنین فهرست متدهای مختص نوع را ببینید).تغییر یافته در نسخهی 3.1: فراخوانی خودکار تابع برابری مختص نوع افزوده شد.
تغییر یافته در نسخهی 3.2:
assertMultiLineEqual()بهعنوان تابع برابری نوع پیشفرض برای مقایسهی رشتهها افزوده شد.
- assertNotEqual(first, second, msg=None)¶
آزمایش میکند که first و second برابر نیستند. اگر مقدارها برابر باشند، آزمون شکست خواهد خورد.
- assertTrue(expr, msg=None)¶
- assertFalse(expr, msg=None)¶
آزمایش میکند که expr درست (یا نادرست) باشد.
توجه داشته باشید که این معادل
bool(expr) is Trueاست و نه معادلexpr is True(برای دومی ازassertIs(expr, True)استفاده کنید). همچنین هنگامی که متدهای خاصتری در دسترس هستند، باید از این متد اجتناب شود (مثلاًassertEqual(a, b)بهجایassertTrue(a == b))، زیرا آنها در صورت شکست، پیام خطای بهتری ارائه میدهند.
- assertIs(first, second, msg=None)¶
- assertIsNot(first, second, msg=None)¶
آزمایش میکند که first و second همان شیء هستند (یا نیستند).
اضافه شده در نسخهی 3.1.
- assertIsNone(expr, msg=None)¶
- assertIsNotNone(expr, msg=None)¶
آزمایش میکند که expr
Noneاست (یا نیست).اضافه شده در نسخهی 3.1.
- assertIn(member, container, msg=None)¶
- assertNotIn(member, container, msg=None)¶
آزمایش میکند که member در container وجود دارد (یا ندارد).
اضافه شده در نسخهی 3.1.
- assertIsInstance(obj, cls, msg=None)¶
- assertNotIsInstance(obj, cls, msg=None)¶
آزمون کنید که obj نمونهای از cls (که میتواند یک کلاس یا تاپلی از کلاسها باشد، همانگونه که
isinstance()پشتیبانی میکند) است (یا نیست). برای بررسی نوع دقیق، ازassertIs(type(obj), cls)استفاده کنید.اضافه شده در نسخهی 3.2.
- assertIsSubclass(cls, superclass, msg=None)¶
- assertNotIsSubclass(cls, superclass, msg=None)¶
بررسی میکند که cls زیرکلاس superclass (که میتواند یک کلاس یا تاپلی از کلاسها باشد، همانطور که
issubclass()پشتیبانی میکند) باشد (یا نباشد). برای بررسی نوع دقیق، ازassertIs(cls, superclass)استفاده کنید.اضافه شده در نسخهی 3.14.
همچنین میتوان تولید استثناها، هشدارها و پیامهای گزارش را با استفاده از متدهای زیر بررسی کرد:
متد
بررسی میکند که
جدید در
fun(*args, **kwds)باعث پرتاب exc میشودfun(*args, **kwds)استثنای exc را پرتاب میکند و پیام آن با عبارت باقاعدهی r مطابقت دارد3.1
fun(*args, **kwds)باعث پرتاب warn میشود3.2
fun(*args, **kwds)موجب پرتاب warn میشود و پیام با عبارت باقاعده r مطابقت دارد3.2
بلوک
withروی logger با حداقل level گزارش میکند3.4
- بلوک
withهیچ پیام گزارشی ثبت نمیکند. logger با حداقل level
3.10
- assertRaises(exception, callable, *args, **kwds)¶
- assertRaises(exception, *, msg=None)
آزمون کنید که وقتی callable با هر آرگومان جایگاهی یا کلیدواژهای که به
assertRaises()نیز ارسال میشود فراخوانی میشود، یک استثنا پرتاب میشود. اگر exception پرتاب شود، آزمون موفق میشود؛ اگر استثنای دیگری پرتاب شود، خطا محسوب میشود؛ و اگر هیچ استثنایی پرتاب نشود، شکست میخورد. برای گرفتن هر یک از استثناهای یک گروه، میتوان یک تاپلشامل کلاسهای استثنا را بهعنوان exception ارسال کرد.اگر تنها آرگومان exception و احتمالاً آرگومان msg داده شده باشند، یک مدیر زمینه برمیگرداند تا کد تحت آزمون بتواند بهصورت درونخطی نوشته شود، نه بهصورت یک تابع:
with self.assertRaises(SomeException): do_something()
هنگام استفاده بهعنوان مدیر زمینه،
assertRaises()آرگومان کلیدواژهای اضافی msg را میپذیرد.مدیر زمینه، شیء استثنای گرفتهشده را در ویژگی
exceptionخود ذخیره میکند. این موضوع میتواند مفید باشد اگر هدف، انجام بررسیهای بیشتر روی استثنای پرتابشده باشد:with self.assertRaises(SomeException) as cm: do_something() the_exception = cm.exception self.assertEqual(the_exception.error_code, 3)
تغییر یافته در نسخهی 3.1: توانایی استفاده از
assertRaises()بهعنوان مدیر زمینه افزوده شد.تغییر یافته در نسخهی 3.2: ویژگی
exceptionاضافه شد.تغییر یافته در نسخهی 3.3: هنگام استفاده بهعنوان مدیر زمینه، آرگومان کلیدواژهای msg اضافه شد.
- assertRaisesRegex(exception, regex, callable, *args, **kwds)¶
- assertRaisesRegex(exception, regex, *, msg=None)
مانند
assertRaises()است، اما همچنین بررسی میکند که regex با نمایش رشتهای استثنای پرتابشده مطابقت داشته باشد. regex میتواند یک شیء عبارت باقاعده یا رشتهای حاوی عبارت باقاعدهای مناسب برای استفاده درre.search()باشد. مثالها:self.assertRaisesRegex(ValueError, "invalid literal for.*XYZ'$", int, 'XYZ')
یا:
with self.assertRaisesRegex(ValueError, 'literal'): int('XYZ')
اضافه شده در نسخهی 3.1: با نام
assertRaisesRegexpاضافه شد.تغییر یافته در نسخهی 3.2: به
assertRaisesRegex()تغییر نام یافت.تغییر یافته در نسخهی 3.3: هنگام استفاده بهعنوان مدیر زمینه، آرگومان کلیدواژهای msg اضافه شد.
- assertWarns(warning, callable, *args, **kwds)¶
- assertWarns(warning, *, msg=None)
آزمون میکند که هنگام فراخوانی callable با هر آرگومان جایگاهی یا کلیدواژهای که به
assertWarns()نیز داده میشود، هشداری فعال میشود. این آزمون در صورتی موفق میشود که warning فعال شود و اگر فعال نشود ناموفق میشود. هر استثنا یک خطا محسوب میشود. برای گرفتن هر یک از هشدارهای یک گروه، میتوان یک تاپل شامل کلاسهای هشدار را بهعنوان warnings ارسال کرد.اگر تنها آرگومانهای warning و احتمالاً msg داده شده باشند، یک مدیر زمینه برمیگرداند تا کد تحت آزمون بتواند بهصورت درونخطی نوشته شود، نه بهصورت یک تابع:
with self.assertWarns(SomeWarning): do_something()
هنگامی که بهعنوان مدیر زمینه استفاده شود،
assertWarns()آرگومان کلیدواژهای اضافی msg را میپذیرد.مدیر زمینه، شیء هشدار گرفتهشده را در ویژگی
warningخود و خط منبعی را که هشدارها را ایجاد کرده است در ویژگیهایfilenameوlinenoذخیره میکند. این میتواند در صورتی مفید باشد که هدف، انجام بررسیهای بیشتر روی هشدار گرفتهشده باشد:with self.assertWarns(SomeWarning) as cm: do_something() self.assertIn('myfile.py', cm.filename) self.assertEqual(320, cm.lineno)
این متد صرفنظر از فیلترهای هشدارِ برقرار در زمان فراخوانی، عمل میکند.
اضافه شده در نسخهی 3.2.
تغییر یافته در نسخهی 3.3: هنگام استفاده بهعنوان مدیر زمینه، آرگومان کلیدواژهای msg اضافه شد.
- assertWarnsRegex(warning, regex, callable, *args, **kwds)¶
- assertWarnsRegex(warning, regex, *, msg=None)
مانند
assertWarns()است، اما همچنین آزمایش میکند که regex با پیام هشدار فعالشده مطابقت دارد. regex میتواند یک شیء عبارت باقاعده یا رشتهای حاوی عبارت باقاعده مناسب برای استفاده توسطre.search()باشد. مثال:self.assertWarnsRegex(DeprecationWarning, r'legacy_function\(\) is deprecated', legacy_function, 'XYZ')
یا:
with self.assertWarnsRegex(RuntimeWarning, 'unsafe frobnicating'): frobnicate('/etc/passwd')
اضافه شده در نسخهی 3.2.
تغییر یافته در نسخهی 3.3: هنگام استفاده بهعنوان مدیر زمینه، آرگومان کلیدواژهای msg اضافه شد.
- assertLogs(logger=None, level=None)¶
یک مدیر زمینه برای آزمایش اینکه حداقل یک پیام با حداقل level دادهشده، روی logger یا یکی از فرزندان آن ثبت شده باشد.
در صورت ارائه، logger باید یک شیء
logging.Loggerیا یکstrباشد که نام یک گزارشگیر را مشخص میکند. مقدار پیشفرض، گزارشگیر ریشه است که تمام پیامهایی را که توسط یک گزارشگیر فرزند بدون انتشار مسدود نشدهاند، دریافت خواهد کرد.در صورت ارائه، level باید یا یک سطح گزارشگیری عددی باشد یا معادل رشتهای آن (برای مثال یا
"ERROR"یاlogging.ERROR). مقدار پیشفرضlogging.INFOاست.اگر حداقل یک پیام منتشرشده درون بلوک
withبا شرایط logger و level مطابقت داشته باشد، آزمون موفق میشود، در غیر این صورت شکست میخورد.شیء برگرداندهشده از سوی مدیر زمینه، یک شیء کمکی برای ضبط است که پیامهای گزارش منطبق را پیگیری میکند. این شیء دو ویژگی دارد:
- records¶
فهرستی از اشیاء
logging.LogRecordمربوط به پیامهای گزارش منطبق.
مثال:
with self.assertLogs('foo', level='INFO') as cm: logging.getLogger('foo').info('first message') logging.getLogger('foo.bar').error('second message') self.assertEqual(cm.output, ['INFO:foo:first message', 'ERROR:foo.bar:second message'])
اضافه شده در نسخهی 3.4.
- assertNoLogs(logger=None, level=None)¶
یک مدیر زمینه برای آزمایش اینکه هیچ پیامی با دستکم level دادهشده، روی logger یا یکی از فرزندان آن ثبت نمیشود.
در صورت ارائه، logger باید یک شیء
logging.Loggerیا یکstrباشد که نام یک گزارشگیر را مشخص میکند. پیشفرض، گزارشگیر ریشه است که تمام پیامها را دریافت میکند.در صورت ارائه، level باید یا یک سطح گزارشگیری عددی باشد یا معادل رشتهای آن (برای مثال یا
"ERROR"یاlogging.ERROR). مقدار پیشفرضlogging.INFOاست.برخلاف
assertLogs()، هیچ چیزی توسط مدیر زمینه برگردانده نخواهد شد.اضافه شده در نسخهی 3.10.
همچنین متدهای دیگری نیز برای انجام بررسیهای خاصتر وجود دارند، مانند:
متد
بررسی میکند که
جدید در
round(a-b, 7) == 0round(a-b, 7) != 0a > b3.1
a >= b3.1
a < b3.1
a <= b3.1
r.search(s)3.1
not r.search(s)3.2
a شامل همان عناصر b است، صرفنظر از ترتیب آنها.
3.2
a.startswith(b)3.14
not a.startswith(b)3.14
a.endswith(b)3.14
not a.endswith(b)3.14
hasattr(a, b)3.14
not hasattr(a, b)3.14
- assertAlmostEqual(first, second, places=7, msg=None, delta=None)¶
- assertNotAlmostEqual(first, second, places=7, msg=None, delta=None)¶
با محاسبهی اختلاف، گرد کردن به تعداد places اعشار دادهشده (پیشفرض ۷)، و مقایسه با صفر، آزمایش میکند که first و second تقریباً برابر هستند (یا تقریباً برابر نیستند). توجه داشته باشید که این متدها مقادیر را به تعداد ارقام اعشار دادهشده گرد میکنند (یعنی مانند تابع
round()) و نه به تعداد ارقام بامعنی.اگر delta بهجای places ارائه شود، اختلاف بین first و second باید کمتر یا مساوی (یا بزرگتر از) delta باشد.
ارائه هر دو delta و places باعث پرتاب
TypeErrorمیشود.تغییر یافته در نسخهی 3.2:
assertAlmostEqual()بهطور خودکار اشیایی را که در مقایسه برابرند، تقریباً برابر در نظر میگیرد.assertNotAlmostEqual()بهطور خودکار اگر اشیاء در مقایسه برابر باشند، شکست میخورد. آرگومان کلیدواژهای delta افزوده شد.
- assertGreater(first, second, msg=None)¶
- assertGreaterEqual(first, second, msg=None)¶
- assertLess(first, second, msg=None)¶
- assertLessEqual(first, second, msg=None)¶
آزمایش میکند که first بسته به نام متد، بهترتیب >، >=، < یا <= از second باشد. در غیر این صورت، آزمون شکست میخورد:
>>> self.assertGreaterEqual(3, 4) AssertionError: "3" unexpectedly not greater than or equal to "4"
اضافه شده در نسخهی 3.1.
- assertRegex(text, regex, msg=None)¶
- assertNotRegex(text, regex, msg=None)¶
آزمایش میکند که یک جستوجوی regex با text مطابقت داشته باشد (یا مطابقت نداشته باشد). در صورت شکست، پیام خطا شامل الگو و text (یا الگو و بخشی از text که بهطور غیرمنتظرهای مطابقت داشت) خواهد بود. regex میتواند یک شیء عبارت باقاعده یا رشتهای حاوی یک عبارت باقاعده مناسب برای استفاده توسط
re.search()باشد.اضافه شده در نسخهی 3.1: با نام
assertRegexpMatchesافزوده شد.تغییر یافته در نسخهی 3.2: متد
assertRegexpMatches()بهassertRegex()تغییر نام یافته است.اضافه شده در نسخهی 3.2:
assertNotRegex().
- assertCountEqual(first, second, msg=None)¶
آزمون میکند که دنبالهی first شامل همان عناصر second است، صرفنظر از ترتیب آنها. در غیر این صورت، پیام خطایی که تفاوتهای بین دنبالهها را فهرست میکند، تولید میشود.
عناصر تکراری هنگام مقایسه first و second نادیده گرفته نمیشوند. این متد بررسی میکند که هر عنصر در هر دو دنباله تعداد یکسانی داشته باشد. معادل است با:
assertEqual(Counter(list(first)), Counter(list(second)))اما با دنبالههایی از اشیاء هشناپذیر (unhashable) نیز کار میکند.اضافه شده در نسخهی 3.2.
- assertStartsWith(s, prefix, msg=None)¶
- assertNotStartsWith(s, prefix, msg=None)¶
آزمایش میکند که رشتهی یونیکدی یا بایتی s با یک prefix آغاز میشود (یا نمیشود). prefix همچنین میتواند تاپلی از رشتهها برای آزمایش باشد.
اضافه شده در نسخهی 3.14.
- assertEndsWith(s, suffix, msg=None)¶
- assertNotEndsWith(s, suffix, msg=None)¶
آزمایش میکند که رشتهی یونیکدی یا بایتی s به یک suffix ختم میشود (یا ختم نمیشود). suffix همچنین میتواند تاپلی از رشتهها برای آزمایش باشد.
اضافه شده در نسخهی 3.14.
- assertHasAttr(obj, name, msg=None)¶
- assertNotHasAttr(obj, name, msg=None)¶
آزمایش میکند که شیء obj ویژگی name را دارد (یا ندارد).
اضافه شده در نسخهی 3.14.
متد
assertEqual()بررسی برابری برای اشیء همنوع را به متدهای مختلف مختص نوع ارجاع میدهد. این متدها از قبل برای بیشتر انواع توکار پیادهسازی شدهاند، اما همچنین امکان ثبت متدهای جدید با استفاده ازaddTypeEqualityFunc()وجود دارد:- addTypeEqualityFunc(typeobj, function)¶
یک متد مختص به نوع را ثبت میکند که توسط
assertEqual()فراخوانی میشود تا بررسی کند که آیا دو شیء از دقیقاً همان typeobj (نه زیرکلاسها) با هم برابر هستند یا خیر. function باید دو آرگومان جایگاهی و یک آرگومان کلیدواژهای سوم به شکل msg=None را بپذیرد، دقیقاً همانطور کهassertEqual()میپذیرد. این تابع باید هنگامی که نابرابری بین دو پارامتر نخست تشخیص داده شود،self.failureException(msg)را پرتاب کند — و در صورت امکان اطلاعات مفیدی ارائه دهد و نابرابریها را با جزئیات در پیام خطا توضیح دهد.اضافه شده در نسخهی 3.1.
فهرست متدهای مختص به نوعی که بهطور خودکار توسط
assertEqual()استفاده میشوند، در جدول زیر خلاصه شده است. توجه داشته باشید که معمولاً نیازی به فراخوانی مستقیم این متدها نیست.متد
برای مقایسه استفاده میشود
جدید در
رشتهها
3.1
دنبالهها
3.1
فهرستها
3.1
تاپلها
3.1
مجموعهها یا مجموعههای فریزشده
3.1
دیکشنریها
3.1
- assertMultiLineEqual(first, second, msg=None)¶
آزمایش میکند که رشته چندخطی first با رشته second برابر باشد. در صورت نابرابر بودن، تفاوت (diff) دو رشته که تفاوتها را برجسته میکند، در پیام خطا گنجانده خواهد شد. این متد بهطور پیشفرض هنگام مقایسه رشتهها با
assertEqual()استفاده میشود.اضافه شده در نسخهی 3.1.
- assertSequenceEqual(first, second, msg=None, seq_type=None)¶
بررسی میکند که دو دنباله برابر باشند. اگر seq_type ارائه شود، هر دو first و second باید نمونههایی از seq_type باشند، در غیر این صورت یک شکست پرتاب خواهد شد. اگر دنبالهها متفاوت باشند، پیام خطایی ساخته میشود که تفاوت میان آن دو را نشان میدهد.
این متد بهطور مستقیم توسط
assertEqual()فراخوانی نمیشود، اما برای پیادهسازیassertListEqual()وassertTupleEqual()از آن استفاده میشود.اضافه شده در نسخهی 3.1.
- assertListEqual(first, second, msg=None)¶
- assertTupleEqual(first, second, msg=None)¶
بررسی میکند که دو فهرست یا تاپل با هم برابر باشند. در غیر این صورت، پیام خطایی ساخته میشود که تنها تفاوتهای میان آن دو را نشان میدهد. همچنین اگر نوع هر یک از پارامترها نادرست باشد، خطایی پرتاب میشود. این متدها بهصورت پیشفرض هنگام مقایسهی فهرستها یا تاپلها با
assertEqual()استفاده میشوند.اضافه شده در نسخهی 3.1.
- assertSetEqual(first, second, msg=None)¶
برابری دو مجموعه را آزمایش میکند. در غیر این صورت، پیام خطایی ساخته میشود که تفاوتهای بین دو مجموعه را فهرست میکند. این متد بهطور پیشفرض هنگام مقایسهی مجموعهها یا frozensetها با
assertEqual()استفاده میشود.اگر هر یک از first یا second متد
difference()را نداشته باشد، شکست میخورد.اضافه شده در نسخهی 3.1.
- assertDictEqual(first, second, msg=None)¶
برابر بودن دو دیکشنری را آزمایش میکند. در غیر این صورت، پیام خطایی ساخته میشود که تفاوتهای موجود در دیکشنریها را نشان میدهد. این متد بهطور پیشفرض برای مقایسهی دیکشنریها در فراخوانیهای
assertEqual()استفاده خواهد شد.اضافه شده در نسخهی 3.1.
در نهایت،
TestCaseمتدها و ویژگیهای زیر را فراهم میکند:- fail(msg=None)¶
بهصورت بیقیدوشرط یک شکست آزمون را اعلام میکند، با msg یا
Noneبرای پیام خطا.
- failureException¶
این ویژگی کلاس، استثنایی را که توسط متد آزمون پرتاب میشود، مشخص میکند. اگر یک چارچوب آزمون نیاز داشته باشد از یک استثنای اختصاصی استفاده کند، احتمالاً برای انتقال اطلاعات اضافی، باید از این استثنا زیرکلاس بسازد تا با چارچوب «منصفانه» رفتار کند. مقدار اولیه این ویژگی
AssertionErrorاست.
- longMessage¶
این صفت کلاس مشخص میکند که چه اتفاقی میافتد هنگامی که یک پیام شکست سفارشی بهعنوان آرگومان msg به یک فراخوانی assertXYY که شکست میخورد ارسال میشود.
Trueمقدار پیشفرض است. در این حالت، پیام سفارشی به انتهای پیام شکست استاندارد اضافه میشود. وقتی رویFalseتنظیم شود، پیام سفارشی جایگزین پیام استاندارد میشود.میتوان تنظیم کلاس را در متدهای آزمون جداگانه با انتساب یک ویژگی نمونه، self.longMessage، به
TrueیاFalseپیش از فراخوانی متدهای assert لغو کرد.تنظیم کلاس پیش از هر فراخوانی آزمون بازنشانی میشود.
اضافه شده در نسخهی 3.1.
- maxDiff¶
این ویژگی حداکثر طول تفاوتها (diffs) در خروجی متدهای assert را که در صورت شکست، تفاوتها را گزارش میکنند، کنترل میکند. مقدار پیشفرض آن ۸۰*۸ نویسه است. متدهای assert که تحت تأثیر این ویژگی هستند، عبارتند از
assertSequenceEqual()(از جمله تمام متدهای مقایسهی دنبالهها که به آن واگذار میشوند)،assertDictEqual()وassertMultiLineEqual().تنظیم
maxDiffرویNoneبه این معناست که برای diffها حداکثر طولی وجود ندارد.اضافه شده در نسخهی 3.2.
چارچوبهای آزمون میتوانند از متدهای زیر برای جمعآوری اطلاعات مربوط به آزمون استفاده کنند:
- countTestCases()¶
تعداد آزمونهایی که این شیء آزمون نشان میدهد را برمیگرداند. برای نمونههای
TestCase، این مقدار همیشه1خواهد بود.
- defaultTestResult()¶
نمونهای از کلاس نتیجه آزمون را برمیگرداند که باید برای این کلاس مورد آزمون استفاده شود (اگر نمونه نتیجه دیگری به متد
run()ارائه نشده باشد).برای نمونههای
TestCase، این همیشه نمونهای ازTestResultخواهد بود؛ زیرکلاسهایTestCaseباید در صورت لزوم این را بازنویسی کنند.
- id()¶
رشتهای را برمیگرداند که مورد آزمون مشخص را شناسایی میکند. این معمولاً نام کامل متد آزمون، شامل نام ماژول و نام کلاس است.
- shortDescription()¶
توضیحی از آزمون را برمیگرداند، یا اگر توضیحی ارائه نشده باشد
Noneبرمیگرداند. پیادهسازی پیشفرض این متد، اولین خط از رشتهی مستند متد آزمون را، در صورت وجود، برمیگرداند، یاNone.تغییر یافته در نسخهی 3.1: در 3.1 این مورد تغییر کرد تا نام آزمون حتی در صورت وجود رشته مستند به توضیح کوتاه اضافه شود. این امر باعث مشکلات سازگاری با افزونههای unittest شد و افزودن نام آزمون در پایتون 3.2 به
TextTestResultمنتقل شد.
- addCleanup(function, /, *args, **kwargs)¶
تابعی را اضافه کنید که پس از
tearDown()برای پاکسازی منابع استفادهشده در طول آزمون فراخوانی شود. توابع به ترتیب معکوس نسبت به ترتیبی که اضافه شدهاند فراخوانی میشوند (LIFO). آنها با هر آرگومان و آرگومان کلیدواژهای که هنگام افزودنشان بهaddCleanup()ارسال شدهاند، فراخوانی میشوند.اگر
setUp()شکست بخورد، به این معنا کهtearDown()فراخوانی نمیشود، هر تابع پاکسازی که اضافه شده باشد همچنان فراخوانی خواهد شد.اضافه شده در نسخهی 3.1.
- enterContext(cm)¶
به مدیر زمینه ارائهشده وارد میشود. در صورت موفقیت، همچنین متد
__exit__()آن را بهعنوان تابع پاکسازی باaddCleanup()اضافه میکند و نتیجهی متد__enter__()را برمیگرداند.اضافه شده در نسخهی 3.11.
- doCleanups()¶
این متد بدون قید و شرط پس از
tearDown()، یا پس ازsetUp()در صورتی فراخوانی میشود کهsetUp()استثنایی را پرتاب کند.این متد مسئول فراخوانی تمام توابع پاکسازی اضافهشده توسط
addCleanup()است. اگر نیاز دارید توابع پاکسازی پیش ازtearDown()فراخوانی شوند، میتوانید خودتانdoCleanups()را فراخوانی کنید.doCleanups()متدها را یکییکی از پشتهی توابع پاکسازی برمیدارد، بنابراین میتوان آن را در هر زمانی فراخوانی کرد.اضافه شده در نسخهی 3.1.
- classmethod addClassCleanup(function, /, *args, **kwargs)¶
یک تابع برای فراخوانی پس از
tearDownClass()اضافه کنید تا منابع استفادهشده در طول کلاس آزمون پاکسازی شوند. توابع به ترتیب معکوس نسبت به ترتیب اضافهشدنشان فراخوانی میشوند (LIFO). آنها با هر آرگومان و آرگومان کلیدواژهای که هنگام اضافهشدنشان بهaddClassCleanup()ارسال شده باشد، فراخوانی میشوند.اگر
setUpClass()شکست بخورد، یعنیtearDownClass()فراخوانی نمیشود، هر یک از توابع پاکسازی اضافهشده همچنان فراخوانی خواهند شد.اضافه شده در نسخهی 3.8.
- classmethod enterClassContext(cm)¶
وارد مدیر زمینه ارائهشده شوید. در صورت موفقیت، متد
__exit__()آن را نیز بهعنوان یک تابع پاکسازی از طریقaddClassCleanup()اضافه کنید و نتیجهی متد__enter__()را برگردانید.اضافه شده در نسخهی 3.11.
- classmethod doClassCleanups()¶
این متد بهصورت غیرشرطی پس از
tearDownClass()، یا در صورتی کهsetUpClass()استثنایی پرتاب کند، پس ازsetUpClass()فراخوانی میشود.این متد مسئول فراخوانی تمام توابع پاکسازی است که توسط
addClassCleanup()افزوده شدهاند. اگر نیاز دارید توابع پاکسازی پیش ازtearDownClass()فراخوانی شوند، میتوانید خودتانdoClassCleanups()را فراخوانی کنید.doClassCleanups()متدها را یکییکی از پشتهی توابع پاکسازی برمیدارد، بنابراین در هر زمانی میتوان آن را فراخوانی کرد.اضافه شده در نسخهی 3.8.
- class unittest.IsolatedAsyncioTestCase(methodName='runTest')¶
این کلاس یک API مشابه
TestCaseارائه میدهد و همچنین همروالها را بهعنوان توابع آزمون میپذیرد.اضافه شده در نسخهی 3.8.
- loop_factory¶
loop_factory که به
asyncio.Runnerداده میشود. در زیرکلاسها آن را باasyncio.EventLoopبازنویسی کنید تا از استفاده از سیستم سیاست asyncio اجتناب شود.اضافه شده در نسخهی 3.13.
- async asyncSetUp()¶
متدی که برای آمادهسازی ثابت آزمایشی آزمون فراخوانی میشود. این متد پس از
TestCase.setUp()فراخوانی میشود. این متد دقیقاً پیش از فراخوانی متد آزمون فراخوانی میشود؛ بهجزAssertionErrorیاSkipTest، هر استثنایی که این متد پرتاب کند، خطا محسوب میشود، نه شکست آزمون. پیادهسازی پیشفرض هیچ کاری انجام نمیدهد.
- async asyncTearDown()¶
متدی که بلافاصله پس از فراخوانی متد آزمون و ثبت نتیجه آن، فراخوانی میشود. این متد پیش از
tearDown()فراخوانی میشود. این متد حتی اگر متد آزمون استثنایی را پرتاب کرده باشد نیز فراخوانی میشود، بنابراین پیادهسازی آن در زیرکلاسها ممکن است نیازمند دقت ویژهای در بررسی وضعیت داخلی باشد. هر استثنایی غیر ازAssertionErrorیاSkipTestکه توسط این متد پرتاب شود، یک خطای اضافی محسوب میشود نه شکست آزمون (بنابراین تعداد کل خطاهای گزارششده را افزایش میدهد). این متد تنها زمانی فراخوانی میشود کهasyncSetUp()موفق شود، صرفنظر از نتیجه متد آزمون. پیادهسازی پیشفرض هیچ کاری انجام نمیدهد.
- addAsyncCleanup(function, /, *args, **kwargs)¶
این متد یک همروال را میپذیرد که میتواند بهعنوان تابع پاکسازی استفاده شود.
- async enterAsyncContext(cm)¶
وارد مدیر زمینه ناهمگام ارائهشده میشود. در صورت موفقیت، همچنین متد
__aexit__()آن را بهعنوان یک تابع پاکسازی از طریقaddAsyncCleanup()اضافه میکند و نتیجهی متد__aenter__()را برمیگرداند.اضافه شده در نسخهی 3.11.
- run(result=None)¶
یک حلقهی رویداد جدید برای اجرای آزمون راهاندازی میکند و نتیجه را در شیء
TestResultکه بهعنوان result ارسال شده است، جمعآوری میکند. اگر result حذف شده باشد یاNoneباشد، یک شیء نتیجهی موقت ایجاد میشود (با فراخوانی متدdefaultTestResult()) و استفاده میشود. شیء نتیجه به فراخوانندهیrun()برگردانده میشود. در پایان آزمون، همهی وظایف موجود در حلقهی رویداد لغو میشوند.
مثالی که ترتیب را نشان میدهد:
from unittest import IsolatedAsyncioTestCase events = [] class Test(IsolatedAsyncioTestCase): def setUp(self): events.append("setUp") async def asyncSetUp(self): self._async_connection = await AsyncConnection() events.append("asyncSetUp") async def test_response(self): events.append("test_response") response = await self._async_connection.get("https://example.com") self.assertEqual(response.status_code, 200) self.addAsyncCleanup(self.on_cleanup) def tearDown(self): events.append("tearDown") async def asyncTearDown(self): await self._async_connection.close() events.append("asyncTearDown") async def on_cleanup(self): events.append("cleanup") if __name__ == "__main__": unittest.main()
پس از اجرای آزمون،
eventsشامل["setUp", "asyncSetUp", "test_response", "asyncTearDown", "tearDown", "cleanup"]خواهد بود.
- class unittest.FunctionTestCase(testFunc, setUp=None, tearDown=None, description=None)¶
این کلاس بخشی از رابط
TestCaseرا پیادهسازی میکند که به اجراگر آزمون اجازه میدهد آزمون را هدایت کند، اما متدهایی را که کد آزمون میتواند برای بررسی و گزارش خطاها از آنها استفاده کند، فراهم نمیکند. این کلاس برای ایجاد موارد آزمون با استفاده از کد آزمون قدیمی به کار میرود و امکان ادغام آن در یک چارچوب آزمون مبتنی برunittestرا فراهم میکند.
گروهبندی آزمونها¶
- class unittest.TestSuite(tests=())¶
این کلاس یک گردآوری از موارد آزمون منفرد و مجموعههای آزمون را نشان میدهد. این کلاس رابط مورد نیاز اجراکننده آزمون را ارائه میکند تا بتوان آن را مانند هر مورد آزمون دیگری اجرا کرد. اجرای یک نمونه
TestSuiteمعادل پیمایش روی بدنهی و اجرای هر آزمون بهصورت جداگانه است.اگر tests داده شود، باید یک پیمایشپذیر از موارد آزمون جداگانه یا سایر بدنههای آزمون باشد که در ابتدا برای ساخت بدنه استفاده میشود. متدهای دیگری برای افزودن موارد آزمون و مجموعهها به این مجموعه در ادامه فراهم شدهاند.
اشیای
TestSuiteبسیار مانند اشیایTestCaseرفتار میکنند، با این تفاوت که در واقع یک آزمون را پیادهسازی نمیکنند. در عوض، از آنها برای جمعآوری آزمونها در گروههایی که باید با هم اجرا شوند استفاده میشود. برخی متدهای اضافی برای افزودن آزمونها به نمونههایTestSuiteدر دسترس هستند:- addTests(tests)¶
تمام آزمونها را از یک پیمایشپذیر شامل نمونههای
TestCaseوTestSuiteبه این بدنهی آزمون اضافه کنید.این معادل پیمایش روی tests و فراخوانی
addTest()برای هر عنصر است.
TestSuiteمتدهای زیر را باTestCaseبه اشتراک میگذارد:- run(result)¶
آزمونهای مرتبط با این بدنه را اجرا میکند و نتیجه را در شیء نتیجه آزمون که بهعنوان result ارسال شده است، جمعآوری میکند. توجه داشته باشید که برخلاف
TestCase.run()،TestSuite.run()نیازمند ارسال شیء نتیجه است.
- debug()¶
آزمونهای مرتبط با این بدنه را بدون جمعآوری نتیجه اجرا کنید. این کار اجازه میدهد استثناهای پرتابشده توسط آزمون به فراخواننده منتقل شوند و میتواند برای پشتیبانی از اجرای آزمونها زیر اشکالزدا استفاده شود.
- countTestCases()¶
تعداد آزمونهای بازنماییشده توسط این شیء آزمون را برمیگرداند، شامل تمام آزمونهای منفرد و زیرمجموعههای آزمون.
- __iter__()¶
آزمونهای گروهبندیشده در یک
TestSuiteهمیشه از طریق پیمایش قابلدسترسی هستند. زیرکلاسها میتوانند با بازنویسی__iter__()، آزمونها را بهصورت تنبل فراهم کنند. توجه داشته باشید که این متد ممکن است چندین بار روی یک بدنه واحد فراخوانی شود (برای مثال هنگام شمارش آزمونها یا مقایسه برای برابری)، بنابراین آزمونهای برگرداندهشده در تکرارهای مکرر پیش ازTestSuite.run()باید برای هر بار فراخوانی یکسان باشند. پس ازTestSuite.run()، فراخوانندهها نباید به آزمونهای برگرداندهشده توسط این متد اتکا کنند، مگر آنکه فراخواننده از زیرکلاسی استفاده کند کهTestSuite._removeTestAtIndex()را برای حفظ ارجاعهای آزمونها بازنویسی کرده باشد.تغییر یافته در نسخهی 3.2: در نسخههای پیشین،
TestSuiteمستقیماً و نه از طریق پیمایش به آزمونها دسترسی پیدا میکرد، بنابراین بازنویسی__iter__()برای فراهم کردن آزمونها کافی نبود.تغییر یافته در نسخهی 3.4: در نسخههای پیشین،
TestSuiteپس ازTestSuite.run()ارجاعهایی به هرTestCaseنگه میداشت. زیرکلاسها میتوانند با بازنویسیTestSuite._removeTestAtIndex()آن رفتار را بازیابی کنند.
در استفادهی معمول از یک شیء
TestSuite، متدrun()توسط یکTestRunnerفراخوانی میشود، نه توسط چارچوب آزمون کاربر نهایی.
بارگذاری و اجرای آزمونها¶
- class unittest.TestLoader¶
از کلاس
TestLoaderبرای ایجاد مجموعههای آزمون از کلاسها و ماژولها استفاده میشود. معمولاً نیازی به ایجاد نمونهای از این کلاس نیست؛ ماژولunittestیک نمونه فراهم میکند که میتوان آن را بهعنوانunittest.defaultTestLoaderبهصورت مشترک استفاده کرد. با این حال، استفاده از یک زیرکلاس یا نمونه، امکان سفارشیسازی برخی ویژگیهای قابلپیکربندی را فراهم میکند.اشیای
TestLoaderدارای ویژگیهای زیر هستند:- errors¶
فهرستی از خطاهای غیرمرگباری که هنگام بارگذاری آزمونها رخ میدهند. این فهرست در هیچ نقطهای توسط بارگذار بازنشانی نمیشود. خطاهای مرگبار با پرتاب استثنا از سوی متد مربوطه به فراخواننده اعلام میشوند. خطاهای غیرمرگبار نیز با یک آزمون مصنوعی نشان داده میشوند که هنگام اجرا، خطای اصلی را پرتاب میکند.
اضافه شده در نسخهی 3.5.
اشیای
TestLoaderمتدهای زیر را دارند:- loadTestsFromTestCase(testCaseClass)¶
یک بدنه آزمون شامل تمام موارد آزمون موجود در
testCaseClassمشتقشده ازTestCaseرا برمیگرداند.برای هر متدی که توسط
getTestCaseNames()نام برده شده باشد، یک نمونه از مورد آزمون ایجاد میشود. بهطور پیشفرض، اینها نام متدهایی هستند که باtestشروع میشوند. اگرgetTestCaseNames()هیچ متدی را برنگرداند، اما متدrunTest()پیادهسازی شده باشد، در عوض یک مورد آزمون واحد برای آن متد ایجاد میشود.
- loadTestsFromModule(module, *, pattern=None)¶
یک بدنه از تمام موارد آزمون موجود در ماژول دادهشده برمیگرداند. این متد در module به دنبال کلاسهایی مشتقشده از
TestCaseمیگردد و برای هر متد آزمون تعریفشده برای آن کلاس، یک نمونه از آن کلاس ایجاد میکند.توجه
در حالی که استفاده از سلسلهمراتبی از کلاسهای مشتقشده از
TestCaseمیتواند بهاشتراکگذاری تدارکات (fixtures) و توابع کمکی را آسان کند، تعریف متدهای آزمون در کلاسهای پایهای که برای نمونهسازی مستقیم در نظر گرفته نشدهاند، با این متد بهخوبی کار نمیکند. با این حال، این کار میتواند زمانی مفید باشد که تدارکات متفاوت باشند و در زیرکلاسها تعریف شده باشند.اگر یک ماژول تابع
load_testsرا فراهم کند، برای بارگذاری آزمونها فراخوانی میشود. این امر به ماژولها امکان میدهد بارگذاری آزمونها را سفارشیسازی کنند. این load_tests protocol است. آرگومان pattern بهعنوان آرگومان سوم بهload_testsارسال میشود.تغییر یافته در نسخهی 3.2: پشتیبانی از
load_testsاضافه شد.تغییر یافته در نسخهی 3.5: پشتیبانی از آرگومان فقط کلیدواژهای pattern اضافه شد.
تغییر یافته در نسخهی 3.12: پارامتر مستندنشده و غیررسمی use_load_tests حذف شده است.
- loadTestsFromName(name, module=None)¶
یک بدنه از تمام موارد آزمون را بر اساس یک مشخصکننده رشتهای برمیگرداند.
مشخصکنندهی name یک «نام نقطهدار» است که ممکن است به یک ماژول، یک کلاس مورد آزمون، یک متد آزمون درون یک کلاس مورد آزمون، یک نمونهی
TestSuite، یا یک شیء قابل فراخوانی که یک نمونهیTestCaseیاTestSuiteرا برمیگرداند، حل شود. این بررسیها به ترتیبی که در اینجا فهرست شدهاند اعمال میشوند؛ یعنی یک متد در یک کلاس مورد آزمون احتمالی، بهعنوان «متد آزمون درون یک کلاس مورد آزمون» شناسایی میشود، نه بهعنوان «شیء فراخوانیپذیر».برای مثال، اگر یک ماژول
SampleTestsداشته باشید که شامل یک کلاس مشتقشده ازTestCaseبه نامSampleTestCaseبا ۳ متد آزمون (test_one()،test_two()وtest_three()) باشد، مشخصکننده'SampleTests.SampleTestCase'باعث میشود این متد یک بدنه آزمون را برگرداند که هر ۳ متد آزمون را اجرا میکند. استفاده از مشخصکننده'SampleTests.SampleTestCase.test_two'باعث میشود آن متد یک بدنه آزمون را برگرداند که فقط متد آزمونtest_two()را اجرا میکند. مشخصکننده میتواند به ماژولها و بستههایی اشاره کند که ایمپورت نشدهاند؛ آنها بهعنوان یک اثر جانبی ایمپورت میشوند.این متد بهصورت اختیاری name را نسبت به module دادهشده حل میکند.
تغییر یافته در نسخهی 3.5: اگر هنگام پیمایش name یک
ImportErrorیاAttributeErrorرخ دهد، یک آزمون مصنوعی که هنگام اجرا آن خطا را پرتاب میکند برگردانده خواهد شد. این خطاها در خطاهای جمعآوریشده توسط self.errors گنجانده میشوند.
- loadTestsFromNames(names, module=None)¶
مشابه
loadTestsFromName()، اما یک دنباله از نامها را بهجای یک نام دریافت میکند. مقدار بازگشتی یک بدنه آزمون (test suite) است که از تمام آزمونهای تعریفشده برای هر نام پشتیبانی میکند.
- getTestCaseNames(testCaseClass)¶
یک دنباله مرتبشده از نام متدهای یافتشده در testCaseClass را برمیگرداند؛ این باید زیرکلاسی از
TestCaseباشد.
- discover(start_dir, pattern='test*.py', top_level_dir=None)¶
همهی ماژولهای آزمون را از پوشه شروع مشخصشده، با پیمایش بازگشتی در زیرپوشهها پیدا میکند و یک شیء TestSuite حاوی آنها را برمیگرداند. فقط پروندههای آزمونی که با pattern مطابقت دارند بارگذاری میشوند. (با استفاده از تطبیق الگو به سبک پوسته.) فقط نام ماژولهایی که قابل ایمپورت هستند (یعنی شناسههای معتبر پایتون هستند) بارگذاری میشوند.
همهی ماژولهای آزمون باید از سطح بالایی پروژه قابل ایمپورت باشند. اگر پوشه شروع، پوشه سطح بالایی نباشد، باید top_level_dir بهطور جداگانه مشخص شود.
اگر ایمپورت یک ماژول با شکست مواجه شود، برای مثال به دلیل خطای سینتکسی، این مورد بهعنوان یک خطای واحد ثبت خواهد شد و کشف ادامه خواهد یافت. اگر علت شکست ایمپورت، پرتاب
SkipTestباشد، بهجای خطا بهعنوان یک پرش ثبت خواهد شد.اگر یک بسته (پوشهای که حاوی پروندهای به نام
__init__.pyاست) یافت شود، بسته از نظر وجود تابعload_testsبررسی میشود. اگر این تابع وجود داشته باشد، بهصورتpackage.load_tests(loader, tests, pattern)فراخوانی میشود. کشف آزمون اطمینان حاصل میکند که یک بسته تنها یک بار در طول یک فراخوانی برای یافتن آزمونها بررسی شود، حتی اگر تابع load_tests خودشloader.discoverرا فراخوانی کند.اگر
load_testsوجود داشته باشد، کشف (discovery) بهصورت بازگشتی وارد بسته نمیشود،load_testsمسئول بارگذاری تمام آزمونها در بسته است.این الگو عمداً بهعنوان یک ویژگی بارگذار ذخیره نمیشود تا بستهها بتوانند خودشان کشف را ادامه دهند.
top_level_dir بهصورت داخلی ذخیره میشود و بهعنوان پیشفرض برای هر فراخوانی تودرتویی از
discover()استفاده میشود. یعنی اگرload_testsیک بسته،loader.discover()را فراخوانی کند، نیازی به ارسال این آرگومان ندارد.start_dir میتواند هم یک نام ماژول نقطهدار و هم یک پوشه باشد.
اضافه شده در نسخهی 3.2.
تغییر یافته در نسخهی 3.4: ماژولهایی که هنگام ایمپورت،
SkipTestرا پرتاب میکنند، بهعنوان پرش ثبت میشوند، نه خطا.start_dir میتواند یک بستهی فضای نام باشد.
مسیرها پیش از ایمپورت شدن مرتب میشوند تا ترتیب اجرا یکسان باشد، حتی اگر ترتیب سامانه فایلبندی زیربنایی به نام پرونده وابسته نباشد.
تغییر یافته در نسخهی 3.5: بستههای یافتشده اکنون از نظر
load_testsبررسی میشوند، صرفنظر از اینکه مسیر آنها با pattern مطابقت داشته باشد، زیرا غیرممکن است که نام یک بسته با الگوی پیشفرض مطابقت داشته باشد.تغییر یافته در نسخهی 3.11: start_dir نمیتواند یک بستهی فضای نام باشد. این از پایتون 3.7 خراب بوده است، و پایتون 3.11 بهطور رسمی آن را حذف میکند.
تغییر یافته در نسخهی 3.13: top_level_dir فقط در طول فراخوانی discover ذخیره میشود.
تغییر یافته در نسخهی 3.14: start_dir میتواند بار دیگر یک namespace package باشد.
ویژگیهای زیرِ یک
TestLoaderرا میتوان یا از طریق زیرکلاسسازی یا با انتساب روی یک نمونه پیکربندی کرد:- testMethodPrefix¶
رشتهای که پیشوند نام متدهایی را که بهعنوان متدهای آزمون تفسیر میشوند، مشخص میکند. مقدار پیشفرض
'test'است.این موضوع بر
getTestCaseNames()و تمام متدهایloadTestsFrom*تأثیر میگذارد.
- sortTestMethodsUsing¶
تابعی که برای مقایسهی نام متدها هنگام مرتبسازی آنها در
getTestCaseNames()و تمام متدهایloadTestsFrom*استفاده میشود.
- suiteClass¶
شیء فراخوانیپذیری که یک بدنه آزمون را از فهرستی از آزمونها میسازد. به هیچ متدی روی شیء حاصل نیازی نیست. مقدار پیشفرض، کلاس
TestSuiteاست.این بر تمام متدهای
loadTestsFrom*تأثیر میگذارد.
- testNamePatterns¶
فهرستی از الگوهای نام آزمون با وایلدکارد به سبک پوستهی Unix که متدهای آزمون برای گنجانده شدن در مجموعههای آزمون باید با آنها مطابقت کنند (گزینهی
-kرا ببینید).اگر این ویژگی
None(پیشفرض) نباشد، تمام متدهای آزمونی که قرار است در مجموعههای آزمون گنجانده شوند، باید با یکی از الگوهای این فهرست مطابقت داشته باشند. توجه داشته باشید که عملیات تطبیق همیشه با استفاده ازfnmatch.fnmatchcase()انجام میشود، بنابراین برخلاف الگوهایی که به گزینهی-kداده میشوند، الگوهای زیررشتهی ساده باید با استفاده از وایلدکارد*تبدیل شوند.این بر تمام متدهای
loadTestsFrom*تأثیر میگذارد.اضافه شده در نسخهی 3.7.
- class unittest.TestResult¶
این کلاس برای جمعآوری اطلاعات دربارهی اینکه کدام آزمونها موفق شدهاند و کدام ناموفق بودهاند استفاده میشود.
یک شیء
TestResultنتایج مجموعهای از آزمونها را ذخیره میکند. کلاسهایTestCaseوTestSuiteتضمین میکنند که نتایج بهدرستی ثبت شوند؛ نویسندگان آزمون نیازی نیست نگران ثبت نتیجه آزمونها باشند.چارچوبهای آزمون ساختهشده بر پایهی
unittestممکن است بخواهند برای اهداف گزارشدهی، به شیءTestResultتولیدشده با اجرای مجموعهای از آزمونها دسترسی داشته باشند؛ برای همین منظور، یک نمونهTestResultتوسط متدTestRunner.run()برگردانده میشود.نمونههای
TestResultدارای ویژگیهای زیر هستند که هنگام بررسی نتایج اجرای مجموعهای از آزمونها مورد توجه خواهند بود:- errors¶
فهرستی شامل تاپلهای دوتایی از نمونههای
TestCaseو رشتههای حاوی ردگیریهای قالببندیشده. هر تاپل نمایانگر آزمونی است که استثنای غیرمنتظرهای را پرتاب کرده است.
- failures¶
فهرستی شامل تاپلهای دوتایی از نمونههای
TestCaseو رشتههای حاوی ردگیریهای پشته قالببندیشده. هر تاپل نشاندهنده آزمونی است که در آن شکستی بهصراحت با استفاده از متدهای assert* اعلام شده است.
- skipped¶
فهرستی شامل تاپلهای دوتایی از نمونههای
TestCaseو رشتههایی که دلیل رد کردن آزمون را در بر دارند.اضافه شده در نسخهی 3.1.
- expectedFailures¶
فهرستی شامل تاپلهای دوتایی از نمونههای
TestCaseو رشتههای حاوی ردگیریهای پشته قالببندیشده. هر تاپل نشاندهندهی یک شکست یا خطای مورد انتظار برای آزمون مربوطه است.
- unexpectedSuccesses¶
فهرستی شامل نمونههای
TestCaseکه بهعنوان شکستهای مورد انتظار علامتگذاری شده بودند، اما موفق شدند.
- collectedDurations¶
فهرستی شامل تاپلهای دوتایی از نامهای موارد آزمون و اعداد اعشاریی که زمان سپریشدهی هر آزمون اجراشده را نشان میدهند.
اضافه شده در نسخهی 3.12.
- testsRun¶
تعداد کل آزمونهای اجراشده تاکنون.
- buffer¶
اگر روی true تنظیم شود،
sys.stdoutوsys.stderrبین فراخوانیstartTest()وstopTest()بافر میشوند. خروجی جمعآوریشده تنها در صورتی رویsys.stdoutوsys.stderrواقعی بازتاب داده میشود که آزمون شکست بخورد یا خطا دهد. هرگونه خروجی نیز به پیام شکست / خطا پیوست میشود.اضافه شده در نسخهی 3.2.
- failfast¶
اگر روی true تنظیم شود، در نخستین شکست یا خطا،
stop()فراخوانی میشود و اجرای آزمون متوقف میشود.اضافه شده در نسخهی 3.2.
- tb_locals¶
اگر روی true تنظیم شود، متغیرهای محلی در ردگیریهای پشته نمایش داده میشوند.
اضافه شده در نسخهی 3.5.
- wasSuccessful()¶
اگر تمام آزمونهایی که تاکنون اجرا شدهاند موفق بوده باشند،
Trueبرمیگرداند، در غیر این صورتFalseبرمیگرداند.تغییر یافته در نسخهی 3.4: اگر هرگونه
unexpectedSuccessesاز آزمونهایی که با دکوراتور@expectedFailureعلامتگذاری شدهاند وجود داشته باشد،Falseرا برمیگرداند.
- stop()¶
این متد را میتوان برای اعلام اینکه بدنه آزمونهای در حال اجرا باید با تنظیم ویژگی
shouldStopرویTrueمتوقف شود، فراخوانی کرد. اشیایTestRunnerباید این پرچم را رعایت کنند و بدون اجرای هیچ آزمون اضافیای بازگردند.برای مثال، این قابلیت توسط کلاس
TextTestRunnerبرای توقف چارچوب آزمون زمانی استفاده میشود که کاربر وقفهای را از صفحهکلید اعلام میکند. ابزارهای تعاملی که پیادهسازیهایTestRunnerرا ارائه میدهند، میتوانند بهصورت مشابهی از این قابلیت استفاده کنند.
متدهای زیر از کلاس
TestResultبرای نگهداری ساختارهای دادهی داخلی استفاده میشوند و میتوانند در زیرکلاسها برای پشتیبانی از نیازمندیهای گزارشدهی بیشتر گسترش یابند. این کار بهویژه هنگام ساخت ابزارهایی که از گزارشدهی تعاملی در حین اجرای آزمونها پشتیبانی میکنند، مفید است.- startTest(test)¶
هنگامی فراخوانی میشود که مورد آزمون test در شرف اجرا باشد.
- stopTest(test)¶
پس از اجرای مورد آزمون test، صرفنظر از نتیجه، فراخوانی میشود.
- startTestRun()¶
یک بار پیش از اجرای هر آزمونی فراخوانی میشود.
اضافه شده در نسخهی 3.1.
- stopTestRun()¶
یک بار پس از اجرای همهی آزمونها فراخوانی میشود.
اضافه شده در نسخهی 3.1.
- addError(test, err)¶
هنگامی فراخوانی میشود که کیس آزمون test یک استثنای غیرمنتظره را پرتاب کند. err یک تاپل با قالبی است که توسط
sys.exc_info()برگردانده میشود:(type, value, traceback).پیادهسازی پیشفرض یک تاپل
(test, formatted_err)را به ویژگیerrorsنمونه اضافه میکند، که در آن formatted_err یک ردگیری پشتهی قالببندیشده است که از err بهدست آمده است.
- addFailure(test, err)¶
هنگامی فراخوانی میشود که مورد آزمون test شکستی را اعلام کند. err یک تاپل با قالبی است که توسط
sys.exc_info()برگردانده میشود:(type, value, traceback).پیادهسازی پیشفرض یک تاپل
(test, formatted_err)را به ویژگیfailuresنمونه میافزاید، که در آن formatted_err یک ردگیری پشته قالببندیشده است که از err بهدست آمده است.
- addSuccess(test)¶
هنگامی که مورد آزمون test موفق باشد، فراخوانی میشود.
پیادهسازی پیشفرض هیچ کاری انجام نمیدهد.
- addSkip(test, reason)¶
هنگامی که مورد آزمون test رد میشود، فراخوانی میشود. reason دلیلی است که آزمون برای رد شدن ارائه کرده است.
پیادهسازی پیشفرض یک تاپل
(test, reason)را به ویژگیskippedنمونه اضافه میکند.
- addExpectedFailure(test, err)¶
هنگامی فراخوانی میشود که مورد آزمون test شکست بخورد یا خطا بدهد، اما با دکوراتور
@expectedFailureعلامتگذاری شده باشد.پیادهسازی پیشفرض، یک تاپل
(test, formatted_err)را به ویژگیexpectedFailuresنمونه میافزاید، که در آن formatted_err یک ردگیری پشتهی قالببندیشده گرفته از err است.
- addUnexpectedSuccess(test)¶
هنگامی فراخوانی میشود که مورد آزمون test با دکوراتور
@expectedFailureعلامتگذاری شده باشد، اما موفق شود.پیادهسازی پیشفرض، آزمون را به ویژگی
unexpectedSuccessesنمونه اضافه میکند.
- addSubTest(test, subtest, outcome)¶
هنگامی که یک زیرآزمون به پایان میرسد، فراخوانی میشود. test مورد آزمون متناظر با متد آزمون است. subtest یک نمونهی سفارشی از
TestCaseاست که زیرآزمون را توصیف میکند.اگر outcome برابر
Noneباشد، زیرآزمون موفق شده است. در غیر این صورت، با یک استثنا شکست خورده است، که در آن outcome یک تاپل بهشکلی است کهsys.exc_info()برمیگرداند:(type, value, traceback).پیادهسازی پیشفرض در صورت موفقیتآمیز بودن نتیجه، کاری انجام نمیدهد و شکستهای زیرآزمون را بهعنوان شکستهای عادی ثبت میکند.
اضافه شده در نسخهی 3.4.
- addDuration(test, elapsed)¶
هنگامی که مورد آزمون به پایان میرسد، فراخوانی میشود. elapsed زمان بر حسب ثانیه است و شامل اجرای توابع پاکسازی نیز میشود.
اضافه شده در نسخهی 3.12.
- class unittest.TextTestResult(stream, descriptions, verbosity, *, durations=None)¶
یک پیادهسازی مشخص از
TestResultکه توسطTextTestRunnerاستفاده میشود. زیرکلاسها باید**kwargsرا بپذیرند تا با تغییر رابط، سازگاری تضمین شود.اضافه شده در نسخهی 3.2.
تغییر یافته در نسخهی 3.12: پارامتر کلیدواژهای durations افزوده شد.
- unittest.defaultTestLoader¶
نمونهای از کلاس
TestLoaderکه برای اشتراکگذاری در نظر گرفته شده است. اگر نیازی به سفارشیسازیTestLoaderنباشد، میتوان بهجای ایجاد مکرر نمونههای جدید، از این نمونه استفاده کرد.
- class unittest.TextTestRunner(stream=None, descriptions=True, verbosity=1, failfast=False, buffer=False, resultclass=None, warnings=None, *, tb_locals=False, durations=None)¶
یک پیادهسازی پایهی اجراکنندهی آزمون که نتایج را به یک جریان خروجی میدهد. اگر stream برابر
Noneباشد (مقدار پیشفرض)، ازsys.stderrبهعنوان جریان خروجی استفاده میشود. این کلاس چند پارامتر قابلپیکربندی دارد، اما اساساً بسیار ساده است. برنامههای گرافیکی که مجموعههای آزمون را اجرا میکنند، باید پیادهسازیهای جایگزین ارائه دهند. چنین پیادهسازیهایی باید**kwargsرا بپذیرند، زیرا وقتی قابلیتهایی به unittest اضافه میشود، رابط ساخت اجراکنندهها تغییر میکند.بهطور پیشفرض، این اجراکننده
DeprecationWarning،PendingDeprecationWarning،ResourceWarningوImportWarningرا نمایش میدهد، حتی اگر بهطور پیشفرض نادیده گرفته شوند. میتوان این رفتار را با استفاده از گزینههای-Wdیا-Waپایتون (به کنترل هشدار مراجعه کنید) و قرار دادن warnings رویNoneلغو کرد.تغییر یافته در نسخهی 3.2: پارامتر warnings افزوده شد.
تغییر یافته در نسخهی 3.2: جریان پیشفرض در زمان نمونهسازی روی
sys.stderrتنظیم میشود، نه در زمان ایمپورت.تغییر یافته در نسخهی 3.5: پارامتر tb_locals افزوده شد.
تغییر یافته در نسخهی 3.12: پارامتر durations افزوده شد.
- _makeResult()¶
این متد نمونهای از
TestResultرا برمیگرداند کهrun()از آن استفاده میکند. این متد برای فراخوانی مستقیم در نظر گرفته نشده است، اما میتوان آن را در زیرکلاسها بازنویسی کرد تا یکTestResultسفارشی فراهم شود._makeResult()کلاس یا فراخوانیپذیر گذراندهشده در سازندهیTextTestRunnerبهعنوان آرگومانresultclassرا نمونهسازی میکند. اگرresultclassارائهنشده باشد، بهطور پیشفرضTextTestResultاستفاده میشود. کلاس نتیجه با آرگومانهای زیر نمونهسازی میشود:stream, descriptions, verbosity
- run(test)¶
این متد رابط عمومی اصلی برای
TextTestRunnerاست. این متد یک نمونه ازTestSuiteیاTestCaseدریافت میکند. یکTestResultبا فراخوانی_makeResult()ایجاد میشود و آزمون(ها) اجرا میشوند و نتایج در stdout چاپ میشوند.
- unittest.main(module='__main__', defaultTest=None, argv=None, testRunner=None, testLoader=unittest.defaultTestLoader, exit=True, verbosity=1, failfast=None, catchbreak=None, buffer=None, warnings=None)¶
برنامهای خطفرمانی که مجموعهای از آزمونها را از module بارگذاری میکند و آنها را اجرا میکند؛ این موضوع عمدتاً برای این است که ماژولهای آزمون بهراحتی قابل اجرا شوند. سادهترین استفاده از این تابع، گنجاندن خط زیر در پایان یک اسکریپت آزمون است:
if __name__ == '__main__': unittest.main()
میتوانید با ارسال آرگومان verbosity، آزمونها را با اطلاعات پرجزئیاتتر اجرا کنید:
if __name__ == '__main__': unittest.main(verbosity=2)
آرگومان defaultTest یا نام یک آزمون منفرد است یا یک پیمایشپذیر از نامهای آزمون برای اجرا، در صورتی که هیچ نام آزمونی از طریق argv مشخص نشده باشد. اگر مشخص نشده باشد یا
Noneباشد و هیچ نام آزمونی از طریق argv ارائه نشده باشد، تمام آزمونهای یافتشده در module اجرا میشوند.آرگومان argv میتواند فهرستی از گزینههای ارسالشده به برنامه باشد، که اولین عنصر آن نام برنامه است. اگر مشخصنشده باشد یا
Noneباشد، مقادیرsys.argvاستفاده میشوند.آرگومان testRunner میتواند یک کلاس اجراکنندهی آزمون یا نمونهای از پیش ایجادشدهی آن باشد. بهطور پیشفرض،
mainsys.exit()را با کد خروجیای فراخوانی میکند که نشاندهندهی موفقیت (۰) یا شکست (۱) آزمونهای اجراشده است. کد خروجی ۵ نشان میدهد که هیچ آزمونی اجرا نشده یا رد شده است.آرگومان testLoader باید نمونهای از
TestLoaderباشد، و مقدار پیشفرض آنdefaultTestLoaderاست.mainاز فراخوانی در مفسر تعاملی با فرستادن آرگومانexit=Falseپشتیبانی میکند. این کار نتیجه را در خروجی استاندارد بدون فراخوانیsys.exit()نمایش میدهد:>>> from unittest import main >>> main(module='test_module', exit=False)
پارامترهای failfast، catchbreak و buffer همان اثر command-line options همنام را دارند.
آرگومان warnings فیلتر هشدار را مشخص میکند که باید هنگام اجرای آزمونها استفاده شود. اگر مشخص نشده باشد، چنانچه گزینهی
-Wبه python داده شود،Noneباقی میماند (به کنترل هشدار مراجعه کنید)، در غیر این صورت روی'default'تنظیم میشود.فراخوانی
mainشیءای را بازمیگرداند که دارای ویژگیresultاست و نتیجهی آزمونهای اجراشده را بهصورت یکunittest.TestResultدر بر دارد.تغییر یافته در نسخهی 3.1: پارامتر exit افزوده شد.
تغییر یافته در نسخهی 3.2: پارامترهای verbosity، failfast، catchbreak، buffer و warnings افزوده شدند.
تغییر یافته در نسخهی 3.4: پارامتر defaultTest تغییر کرد تا یک پیمایشپذیر از نام آزمونها را نیز بپذیرد.
پروتکل load_tests¶
اضافه شده در نسخهی 3.2.
ماژولها یا بستهها میتوانند با پیادهسازی تابعی به نام load_tests، نحوه بارگذاری آزمونها از آنها را در حین اجراهای عادی آزمون یا کشف آزمون سفارشی کنند.
اگر یک ماژول آزمون load_tests را تعریف کند، توسط TestLoader.loadTestsFromModule() با آرگومانهای زیر فراخوانی میشود:
load_tests(loader, standard_tests, pattern)
که در آن pattern بدون تغییر از loadTestsFromModule ارسال میشود. مقدار پیشفرض آن None است.
باید یک TestSuite برگرداند.
loader نمونهای از TestLoader است که بارگذاری را انجام میدهد. standard_tests آزمونهایی هستند که بهطور پیشفرض از ماژول بارگذاری میشوند. رایج است که ماژولهای آزمون فقط بخواهند آزمونهایی را به مجموعه استاندارد آزمونها اضافه یا از آن حذف کنند. آرگومان سوم هنگام بارگذاری بستهها بهعنوان بخشی از کشف آزمون استفاده میشود.
یک تابع معمول load_tests که آزمونها را از مجموعه مشخصی از کلاسهای TestCase بارگذاری میکند، ممکن است به شکل زیر باشد:
test_cases = (TestCase1, TestCase2, TestCase3)
def load_tests(loader, tests, pattern):
suite = TestSuite()
for test_class in test_cases:
tests = loader.loadTestsFromTestCase(test_class)
suite.addTests(tests)
return suite
اگر کشف در پوشهای حاوی یک بسته آغاز شود، چه از خط فرمان و چه با فراخوانی TestLoader.discover()، پرونده __init__.py بسته از نظر load_tests بررسی میشود. اگر آن تابع وجود نداشته باشد، کشف بهصورت بازگشتی وارد بسته میشود، گویی که صرفاً پوشهای دیگر است. در غیر این صورت، کشف آزمونهای بسته به load_tests واگذار میشود که با آرگومانهای زیر فراخوانی میشود:
load_tests(loader, standard_tests, pattern)
این باید یک TestSuite را برگرداند که تمام آزمونهای بسته را نشان میدهد. (standard_tests فقط شامل آزمونهای جمعآوریشده از __init__.py خواهد بود.)
از آنجا که الگو به load_tests پاس داده میشود، بسته مختار است که کشف آزمون را ادامه دهد (و احتمالاً آن را تغییر دهد). یک تابع load_tests با عملکرد «هیچکاری نکردن» برای یک بسته آزمون به شکل زیر خواهد بود:
def load_tests(loader, standard_tests, pattern):
# top level directory cached on loader instance
this_dir = os.path.dirname(__file__)
package_tests = loader.discover(start_dir=this_dir, pattern=pattern)
standard_tests.addTests(package_tests)
return standard_tests
تغییر یافته در نسخهی 3.5: کشف دیگر نام بستهها را برای تطبیق با pattern بررسی نمیکند، زیرا تطبیق نام بستهها با الگوی پیشفرض غیرممکن است.
ثابتهای آزمایشی کلاس و ماژول (fixtures)¶
ثابتهای آزمایشی سطح کلاس و ماژول (fixtures) در TestSuite پیادهسازی شدهاند. هنگامی که بدنه آزمون با آزمونی از یک کلاس جدید مواجه میشود، tearDownClass() از کلاس پیشین (در صورت وجود) فراخوانی میشود و پس از آن setUpClass() از کلاس جدید فراخوانی میشود.
بهطور مشابه، اگر یک آزمون از ماژولی متفاوت از آزمون قبلی باشد، tearDownModule از ماژول قبلی اجرا میشود و سپس setUpModule از ماژول جدید اجرا میشود.
پس از اجرای همهی آزمونها، در نهایت tearDownClass و tearDownModule اجرا میشوند.
توجه داشته باشید که ثابتهای آزمایشی مشترک (shared fixtures) با قابلیتهای [بالقوه] مانند موازیسازی آزمونها سازگاری خوبی ندارند و جداسازی آزمونها را نقض میکنند. باید با احتیاط از آنها استفاده شود.
ترتیب پیشفرض آزمونهای ایجادشده توسط بارگذارهای آزمون unittest، گروهبندی همه آزمونهای مربوط به ماژولها و کلاسهای یکسان در کنار یکدیگر است. این موضوع باعث میشود setUpClass / setUpModule (و غیره) دقیقاً یکبار برای هر کلاس و ماژول فراخوانی شوند. اگر ترتیب را تصادفی کنید، بهطوری که آزمونهایی از ماژولها و کلاسهای مختلف مجاور یکدیگر قرار بگیرند، ممکن است این توابع ثابت آزمایشی (fixture) مشترک چندین بار در یک اجرای آزمون فراخوانی شوند.
ثابتهای آزمایشی مشترک برای کار با مجموعههای آزمونی که ترتیب غیراستاندارد دارند در نظر گرفته نشدهاند. BaseTestSuite همچنان برای چارچوبهایی که نمیخواهند از ثابتهای آزمایشی مشترک پشتیبانی کنند وجود دارد.
اگر در حین یکی از توابع ثابت آزمایشی (fixture) مشترک، استثنایی پرتاب شود، آزمون بهعنوان خطا گزارش میشود. از آنجا که هیچ نمونه آزمون متناظری وجود ندارد، یک شیء _ErrorHolder (که همان رابط TestCase را دارد) برای نمایش خطا ایجاد میشود. اگر صرفاً از اجراکنندهی آزمون استاندارد unittest استفاده میکنید، این جزئیات اهمیتی ندارد، اما اگر نویسنده یک چارچوب هستید، ممکن است مرتبط باشد.
setUpClass و tearDownClass¶
اینها باید بهصورت متدهای کلاس پیادهسازی شوند:
import unittest
class Test(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls._connection = createExpensiveConnectionObject()
@classmethod
def tearDownClass(cls):
cls._connection.destroy()
اگر میخواهید setUpClass و tearDownClass در کلاسهای پایه فراخوانی شوند، باید خودتان آنها را فراخوانی کنید. پیادهسازیها در TestCase خالی هستند.
اگر یک استثنا در حین setUpClass پرتاب شود، آنگاه آزمونهای درون کلاس اجرا نمیشوند و tearDownClass نیز اجرا نمیشود. برای کلاسهای ردشده، setUpClass یا tearDownClass اجرا نخواهد شد. اگر استثنا یک استثنای SkipTest باشد، کلاس بهجای خطا بهعنوان ردشده گزارش میشود.
setUpModule و tearDownModule¶
این موارد باید بهصورت تابع پیادهسازی شوند:
def setUpModule():
createConnection()
def tearDownModule():
closeConnection()
اگر در setUpModule استثنایی پرتاب شود، هیچکدام از آزمونهای ماژول اجرا نخواهند شد و tearDownModule اجرا نخواهد شد. اگر استثنا یک استثنای SkipTest باشد، ماژول بهجای آنکه بهعنوان خطا گزارش شود، بهعنوان ردشده گزارش خواهد شد.
برای افزودن کد پاکسازی که باید حتی در صورت وقوع استثنا نیز اجرا شود، از addModuleCleanup استفاده کنید:
- unittest.addModuleCleanup(function, /, *args, **kwargs)¶
یک تابع برای فراخوانی پس از
tearDownModule()اضافه کنید تا منابع استفادهشده در طول کلاس آزمون پاکسازی شوند. توابع به ترتیب معکوس نسبت به ترتیبی که اضافه شدهاند فراخوانی خواهند شد (LIFO). این توابع با هر آرگومان و آرگومان کلیدواژهای که هنگام اضافه شدن آنها بهaddModuleCleanup()ارسال شده باشد، فراخوانی میشوند.اگر
setUpModule()با شکست مواجه شود، به این معنا کهtearDownModule()فراخوانی نمیشود، هر تابع پاکسازی که اضافهشده باشد همچنان فراخوانی خواهد شد.اضافه شده در نسخهی 3.8.
- unittest.enterModuleContext(cm)¶
وارد context manager ارائهشده میشود. در صورت موفقیت، متد
__exit__()آن را نیز بهعنوان تابع پاکسازی از طریقaddModuleCleanup()اضافه میکند و نتیجهی متد__enter__()را برمیگرداند.اضافه شده در نسخهی 3.11.
- unittest.doModuleCleanups()¶
این تابع بدون شرط پس از
tearDownModule()، یا پس ازsetUpModule()در صورتی فراخوانی میشود کهsetUpModule()استثنایی را پرتاب کند.این تابع مسئول فراخوانی همهی توابع پاکسازی افزودهشده توسط
addModuleCleanup()است. اگر نیاز دارید توابع پاکسازی پیش ازtearDownModule()فراخوانی شوند، میتوانید خودتانdoModuleCleanups()را فراخوانی کنید.doModuleCleanups()متدها را یکییکی از پشتهی توابع پاکسازی برمیدارد، بنابراین میتوان آن را در هر زمانی فراخوانی کرد.اضافه شده در نسخهی 3.8.
مدیریت سیگنال¶
اضافه شده در نسخهی 3.2.
گزینهی خط فرمان -c/--catch برای unittest، بههمراه پارامتر catchbreak برای unittest.main()، مدیریت مناسبتری برای control-C در طول اجرای آزمون فراهم میکنند. با فعال بودن رفتار catch break، control-C اجازه میدهد آزمون در حال اجرا کامل شود و سپس اجرای آزمون پایان مییابد و تمام نتایج تا آن لحظه را گزارش میدهد. دومین control-c، KeyboardInterrupt را به روش معمول پرتاب میکند.
هندلر سیگنال رسیدگی به control-c تلاش میکند با کد یا آزمونهایی که هندلر signal.SIGINT خودشان را نصب میکنند سازگار باقی بماند. اگر هندلر unittest فراخوانی شود اما هندلر signal.SIGINT نصبشده نباشد، یعنی سیستم تحت آزمون آن را جایگزین کرده و به آن واگذار کرده باشد، آنگاه هندلر پیشفرض را فراخوانی میکند. این معمولاً رفتار مورد انتظار کدی خواهد بود که یک مدیر نصبشده را جایگزین میکند و به آن واگذار مینماید. برای آزمونهای تکی که نیاز دارند رسیدگی unittest به control-c غیرفعال شود، میتوان از دکوراتور removeHandler() استفاده کرد.
چند تابع کاربردی برای نویسندگان چارچوب وجود دارد تا قابلیت مدیریت control-c را در چارچوبهای آزمون فعال کنند.
- unittest.installHandler()¶
هندلری control-c را نصب کنید. هنگامی که
signal.SIGINTدریافت میشود (معمولاً در پاسخ به فشردهشدن control-c توسط کاربر)، برای همهی نتایج ثبتشده،stop()فراخوانی میشود.
- unittest.registerResult(result)¶
یک شیء
TestResultرا برای مدیریت control-c ثبت میکند. ثبت یک نتیجه، ارجاع ضعیفی به آن ذخیره میکند، بنابراین از زبالهروبی شدن نتیجه جلوگیری نمیکند.ثبت یک شیء
TestResultدر صورتی که مدیریت control-c فعال نباشد، هیچ عارضهی جانبی ندارد؛ بنابراین چارچوبهای آزمون میتوانند بهصورت غیرمشروط تمام نتایجی را که ایجاد میکنند، مستقل از فعال بودن یا نبودن مدیریت، ثبت کنند.
- unittest.removeResult(result)¶
حذف یک نتیجه ثبتشده. پس از حذف یک نتیجه،
stop()دیگر روی آن شیء نتیجه در پاسخ به control-c فراخوانی نخواهد شد.
- unittest.removeHandler(function=None)¶
هنگامی که این تابع بدون آرگومان فراخوانی شود، هندلر control-c را در صورت نصبشده بودن حذف میکند. این تابع همچنین میتواند بهعنوان دکوراتور آزمون برای حذف موقت هندلر در حین اجرای آزمون استفاده شود:
@unittest.removeHandler def test_signal_handling(self): ...