نحوه تست کد پایتون با استفاده از ماژول unittest

شما باید در حین توسعه نرم افزار یا یک برنامه وب، توابع متعدد و یک سری کارها را نوشته باشید. این توابع و وظایف باید به درستی کار کنند. اگر در کد با خطا مواجه شویم، اشکال زدایی مشکل می شود.
یک تمرین خوب این است که کد خود را به واحدها یا قطعات کوچک تقسیم کنیم و آنها را به طور مستقل آزمایش کنیم تا مطمئن شویم که به درستی کار می کنند.
پایتون یک ماژول داخلی به نام ارائه می کند unittest
که به ما امکان می دهد تست های واحد را بنویسیم و اجرا کنیم.
شروع به کار با unittest
را unittest
ماژول شامل تعدادی روش و کلاس برای ایجاد و اجرای موارد تست است. بیایید به یک مثال ساده نگاه کنیم که در آن از آن استفاده کردیم unittest
ماژول برای ایجاد یک مورد آزمایشی.
# basic.py
import unittest
class TestSample(unittest.TestCase):
def test_equal(self):
self.assertEqual(round(3.155), 3.0)
def test_search(self):
self.assertIn("G", "Geek")
اول، ما وارد کردیم unittest
ماژول، که ما را قادر می سازد از کلاس هایی استفاده کنیم که برای نوشتن و اجرای موارد تست استفاده می شود.
را TestSample
کلاس تعریف شده است که از the ارث می برد unittest.TestCase
که به ما امکان استفاده از انواع مختلف را می دهد روش های ادعا در موارد آزمایشی ما
ما دو روش تست را در خود تعریف کردیم TestSample
کلاس: test_equal
و test_search
.
روش تست test_equal()
آزمایشات اگر round(3.155)
برابر است با 3.0
با استفاده از assertEqual()
روش ادعا
روش تست test_search()
آزمایش می کند که آیا شخصیت "G"
در رشته وجود دارد "Geek"
با استفاده از assertIn()
روش ادعا
برای اجرای این تست ها باید دستور زیر را در ترمینال اجرا کنیم.
python -m unittest basic.py
این دستور راه اندازی می شود unittest
به عنوان یک ماژول که تست ها را جستجو و اجرا می کند basic.py
فایل.
توجه داشته باشید که unittest
ماژول فقط آن متدهایی را که با آن شروع می شوند کشف و اجرا می کند test_
یا test
.
به هر حال، این نقاط نشان دهنده یک آزمایش موفق است.
ما می توانیم استفاده کنیم unittest.main()
تابع را اجرا کنید و آن را به شکل زیر در انتهای اسکریپت تست قرار دهید تا تست ها از ماژول بارگذاری و اجرا شوند.
if __name__ == '__main__':
unittest.main()
این به ما امکان می دهد فایل آزمایشی خود را اجرا کنیم، basic.py
در این مورد، به عنوان ماژول اصلی.
نتیجه دقیق تر
ما می توانیم استفاده کنیم -v
در ترمینال پرچم گذاری کنید یا آرگومان ارسال کنید verbosity=2
درون unittest.main()
عملکرد برای دریافت خروجی دقیق از آزمون.
روش های متداول مورد استفاده برای ادعا
در اینجا فهرستی از متداولترین روشهای ادعایی مورد استفاده در تست واحد آورده شده است.
روش | آن را بررسی می کند |
---|---|
assertEqual(a, b) |
a == b |
assertNotEqual(a, b) |
a != b |
assertTrue(x) |
bool(x) is True |
assertFalse(x) |
bool(x) is False |
assertIs(a, b) |
a is b |
assertIsNot(a, b) |
a is not b |
assertIsNone(x) |
x is None |
assertIsNotNone(x) |
x is not None |
assertIn(a, b) |
a in b |
assertNotIn(a, b) |
a not in b |
assertIsInstance(a, b) |
isinstance(a, b) |
assertNotIsInstance(a, b) |
not isinstance(a, b) |
مثال
فرض کنید ما مقداری کد داریم و میخواهیم با استفاده از کد واحد تست واحد را روی آن انجام دهیم unittest
مدول.
# triangle.py
class Triangle:
def __init__(self, base, height):
self.base = base
self.height = height
def area(self):
return 0.5 * self.base * self.height
def perimeter(self, side):
return self.base + self.height + side
کد کلاسی به نام تعریف می کند Triangle
که یک متد init دارد که شی را با متغیرهای نمونه مقداردهی اولیه می کند self.base
و self.height
.
دو روش دیگر در Triangle
کلاس: area()
و perimeter()
.
را area()
روش مساحت مثلث را که نصف حاصلضرب قاعده و ارتفاع (0.5 * self.base * self.height
).
روش parameter()
پارامتری به نام را می پذیرد side
، و چون پارامتر مثلث مجموع سه ضلع آن است base
و height
متغیرها جای دو طرف دیگر را می گیرند.
حالا میتوانیم یک فایل پایتون دیگر ایجاد کنیم که در آن چند تست بنویسیم و سپس آنها را اجرا کنیم.
# test_sample.py
from triangle import Triangle
import unittest
class TestTriangle(unittest.TestCase):
t = Triangle(9, 8)
def test_area(self):
self.assertEqual(self.t.area(), 36)
def test_perimeter(self):
self.assertEqual(self.t.perimeter(5), 22)
def test_valid_base(self):
self.assertGreater(self.t.base, 0)
def test_valid_height(self):
self.assertGreater(self.t.height, 0)
if __name__ == '__main__':
unittest.main(verbosity=2)
کد بالا را وارد می کند Triangle
کلاس از triangle
مدول (triangle.py
فایل) و همچنین وارد می کند unittest
ماژول برای نوشتن موارد تست.
را TestTriangle
کلاس از the به ارث می برد unittest.TestCase
که چهار روش تست دارد. را Triangle
کلاس با الف شروع شد base
از 9
و height
از 8
و در داخل متغیر ذخیره می شود t
.
را test_area
روش تست می کند که آیا self.t.area()
برابر با نتیجه مورد انتظار است 36
با استفاده از assertEqual()
ادعا
را test_perimeter
روش تست می کند که آیا self.t.perimeter(5)
برابر است با 22
با استفاده از assertEqual()
ادعا
را test_valid_base
و test_valid_height
روش هایی برای آزمایش اینکه آیا پایه (self.t.base
) و ارتفاع (self.t.height
) از مثلث بزرگتر از 0
با استفاده از assertGreater()
ادعا
را unittest.main(verbosity=2)
متد تست ها را از روی بازیابی و اجرا می کند TestTriangle
کلاس ما یک خروجی دقیق دریافت خواهیم کرد زیرا از آن استفاده کردیم verbosity=2
بحث و جدل.
آزمون استثنایی
اگر قبلاً از عبارات assert استفاده کرده باشید، میدانید که وقتی یکی با شکست مواجه میشود، یک عدد را پرتاب میکند AssertionError
. به طور مشابه، هر زمان که یک روش تست شکست بخورد، یک AssertionError
ظهور کرده.
میتوانیم شرایطی را که در آن کد ما خطا ایجاد میکند، از پیش تعیین کنیم و سپس آن شرایط را آزمایش کنیم تا ببینیم آیا خطا ایجاد میکنند یا خیر. این امکان با assertRaises()
روش.
را assertRaises()
روش را می توان با مدیریت زمینه استفاده کرد، بنابراین ما از آن به شکل زیر استفاده خواهیم کرد:
def test_method(self):
with assertRaises(exception_name):
function_name(argument)
تابع زیر را در نظر بگیرید gen_odd()
، که یک سری اعداد فرد را تا آرگومان تولید می کند n
با افزایش num
توسط 3
و فقط شامل چند بررسی است که در آن استدلال n
باید از نوع باشد int
و بزرگتر از 0
.
# odd.py
def gen_odd(n):
if type(n) != int:
raise TypeError("Invalid argument type.")
if n < 0:
raise ValueError("Value must be greater than 0.")
num = 0
while num <= n:
if num % 2 == 1:
print(num)
num += 3
اکنون روشهای آزمایشی را برای شبیهسازی شرایطی که ممکن است باعث شکست کد بالا شود، مینویسیم.
from odd import gen_odd
import unittest
class OddTestCase(unittest.TestCase):
def test_negative_val(self):
with self.assertRaises(ValueError):
gen_odd(-5)
def test_float_val(self):
with self.assertRaises(TypeError):
gen_odd(99.9)
def test_string_val(self):
with self.assertRaises(TypeError):
gen_odd('10')
if __name__ == '__main__':
unittest.main(verbosity=2)
ما سه روش تست را در آن نوشتیم OddTestCase
کلاس برای اطمینان از اینکه وقتی آرگومان های نامعتبر ارسال می شوند، خطای مربوطه ایجاد می شود.
را test_negative_val()
روش ادعا می کند که ValueError
زمانی مطرح می شود که gen_odd(-5)
نامیده میشود.
به طور مشابه، test_float_val()
و test_string_val()
روش ها ادعا می کنند که وقتی gen_odd(99.9)
و gen_odd('10')
به ترتیب نامیده می شوند TypeError
ظهور کرده.
هر سه تست موجود در کد بالا قبول شدند، به این معنی که همه آنها خطاهای مربوطه را مطرح کردند، در غیر این صورت، اگر استثنا دیگری مطرح می شد، تست ها شکست می خوردند یا خطاها را افزایش می دادند. بیایید آن را آزمایش کنیم.
from odd import gen_odd
import unittest
class OddTestCase(unittest.TestCase):
def test_valid_arg(self):
with self.assertRaises(TypeError, msg="Valid argument"):
gen_odd(10)
if __name__ == '__main__':
unittest.main(verbosity=2)
شرایط فوق در داخل test_valid_arg()
روش یک پرتاب نمی کند TypeError
زیرا gen_odd()
تابع با یک آرگومان معتبر ارسال می شود.
روش تست بالا شکست خورد و باعث شد یک AssertionError
با پیام TypeError not raised : Valid argument
.
رد شدن از آزمون ها
را unittest
از skip()
دکوراتور یا skipTest()
برای رد شدن از هر روش آزمایشی یا کل کلاس آزمایشی عمداً، و ما باید دلیل حذف آزمون را مشخص کنیم.
کد مثال قبلی را در نظر بگیرید که با اضافه کردن کد آن را اصلاح کردیم skip()
دکوراتور
from odd import gen_odd
import unittest
class OddTestCase(unittest.TestCase):
@unittest.skip("Valid argument")
def test_valid_arg(self):
with self.assertRaises(TypeError):
gen_odd(10)
if __name__ == '__main__':
unittest.main(verbosity=2)
واضح است که شرط بالا از کار می افتد و یک را پرتاب می کند AssertionError
، بنابراین آزمایش را عمداً رد کردیم.
اگر بخواهیم در صورت صحت یک شرط خاص از آزمون صرف نظر کنیم، چه؟ ما می توانیم این کار را با استفاده از skipIf()
دکوراتور، که به ما امکان می دهد یک شرط را مشخص کنیم و در صورت صحت از آزمایش صرف نظر کنیم.
from odd import gen_odd
import sys
import unittest
class OddTestCase(unittest.TestCase):
@unittest.skipIf(sys.getsizeof(gen_odd(10)) > 10, "Exceeded limit")
def test_memory_use(self):
self.assertTrue(sys.getsizeof(gen_odd(10)) > 10)
print(f"Size: {sys.getsizeof(gen_odd(10))} bytes")
if __name__ == '__main__':
unittest.main(verbosity=2)
شرط در بالا skipIf()
دکوراتور بررسی می کند که آیا اندازه gen_odd(10)
بزرگتر است از 10
بایت، اگر شرط باشد درست است، واقعی، روش تست test_memory_use()
حذف می شود، در غیر این صورت، آزمون اجرا می شود.
شکست مورد انتظار
اگر یک روش تست یا کلاس تست با شرایطی داریم که انتظار می رود نادرست باشد، می توانیم از آن استفاده کنیم expectedFailure()
دکوراتور به جای بررسی خطاها، آنها را به عنوان شکست های مورد انتظار علامت گذاری کند.
from odd import gen_odd
import sys
import unittest
class OddTestCase(unittest.TestCase):
@unittest.expectedFailure
def test_memory_use(self):
self.assertTrue(sys.getsizeof(gen_odd(10)) < 10, msg="Expected to be failed")
print(f"Size: {sys.getsizeof(gen_odd(10))} bytes")
if __name__ == '__main__':
unittest.main(verbosity=2)
ما کد قبلی و شرایطی را که در داخل آن بررسی می کنیم، اصلاح کرده ایم test_memory_use()
انتظار می رود که روش نادرست باشد، به همین دلیل است که روش با زینت داده شده است @unittest.expectedFailure
دکوراتور
نتیجه
ما می توانیم استفاده کنیم unittest
ماژول برای نوشتن و اجرای آزمایش ها برای اطمینان از اینکه کد به درستی کار می کند. آزمایش می تواند به یکی از سه نتیجه منجر شود: OK، FAIL یا Error.
را unittest
ماژول چندین روش ادعا را ارائه می دهد که برای اعتبارسنجی کد استفاده می شود.
بیایید آنچه را که یاد گرفتیم به یاد بیاوریم:
-
استفاده اساسی از
unittest
مدول. -
دستورات CLI برای اجرای تست ها.
-
آزمایش اینکه آیا این شرایط استثنایی ایجاد می کند.
-
رد شدن از آزمایش ها به صورت عمدی و زمانی که یک شرط خاص درست است.
-
علامت گذاری یک آزمون به عنوان یک شکست مورد انتظار
اگر این مقاله را دوست داشتید، ممکن است به مقالات دیگری علاقه مند شوید
چگونه از دستورات ادعا برای اشکال زدایی در پایتون استفاده کنیم؟
کاربردهای ستاره چیست
در پایتون؟
متدهای __init__ و __new__ در پایتون چیست؟
چگونه getitem، setitem و delitem را در کلاس های پایتون پیاده سازی کنیم؟
چگونه با استفاده از متدهای str و repr نمایش رشته شی را تغییر دهیم؟
چگونه با استفاده از tempfile در پایتون فایل ها و دایرکتوری های موقت تولید کنیم؟
یک مدل یادگیری عمیق سفارشی با استفاده از تکنیک آموزش انتقال بسازید.
فعلاً همین است
به کدنویسی ادامه دهید