تست نویسی در پایتون چیست؟
آموزش تست نویسی در Python با
assert
و کتابخانه
unittest
تست نویسی چیست؟
وقتی یک برنامه پایتونی مینویسیم، باید مطمئن شویم که برنامه در شرایط مختلف درست کار میکند. یکی از روشهای مهم برای بررسی عملکرد برنامه، تست نویسی (Testing) است.
در تست نویسی، قسمتهای مختلف برنامه را با ورودیهای مشخص اجرا میکنیم و بررسی میکنیم که خروجی همان چیزی باشد که انتظار داریم.
تستها مخصوصاً در پروژههای بزرگ بسیار مهم هستند؛ زیرا با تغییر دادن یک قسمت از برنامه میتوانیم بررسی کنیم که قسمتهای قبلی همچنان درست کار میکنند.
چرا تست نویسی مهم است؟
- پیدا کردن خطاهای برنامه
- جلوگیری از ایجاد خطاهای جدید
- اطمینان از عملکرد صحیح توابع
- آسانتر شدن توسعه پروژههای بزرگ
- افزایش کیفیت و قابل اعتماد بودن کد
دستور assert در پایتون
یکی از سادهترین روشها برای بررسی یک شرط در پایتون،
استفاده از دستور
assert
است.
x = 10
assert x == 10
اگر شرط درست باشد، برنامه بدون خطا ادامه پیدا میکند.
اما اگر شرط نادرست باشد، پایتون خطای
AssertionError
ایجاد میکند.
مثال ساده با assert
def add(a, b):
return a + b
result = add(2, 3)
assert result == 5
در این مثال بررسی میکنیم که نتیجه تابع
add()
برابر با
5
باشد.
کتابخانه unittest چیست؟
پایتون یک کتابخانه داخلی به نام
unittest
دارد که برای نوشتن و اجرای تستها استفاده میشود.
برای استفاده از آن نیازی به نصب پکیج جداگانه نداریم.
import unittest
اولین تست با unittest
ابتدا یک تابع ساده ایجاد میکنیم:
def add(a, b):
return a + b
سپس برای آن یک کلاس تست ایجاد میکنیم:
import unittest
def add(a, b):
return a + b
class TestAdd(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)
if __name__ == "__main__":
unittest.main()
متد
test_add()
یک تست برای تابع
add()
است.
TestCase چیست؟
برای ساخت تستها معمولاً از کلاس
unittest.TestCase
استفاده میکنیم.
class TestCalculator(unittest.TestCase):
def test_add(self):
self.assertEqual(2 + 3, 5)
کلاس تست باید از
TestCase
ارثبری کند.
مهمترین Assertion ها در unittest
کتابخانه
unittest
چندین متد برای بررسی نتایج در اختیار ما قرار میدهد.
assertEqual
self.assertEqual(2 + 2, 4)
بررسی میکند که دو مقدار برابر باشند.
assertNotEqual
self.assertNotEqual(2 + 2, 5)
بررسی میکند که دو مقدار برابر نباشند.
assertTrue
self.assertTrue(10 > 5)
assertFalse
self.assertFalse(10 < 5)
assertIn
self.assertIn("Python", ["Python", "Java", "C++"])
assertNotIn
self.assertNotIn("PHP", ["Python", "Java", "C++"])
نوشتن چند تست برای یک تابع
import unittest
def multiply(a, b):
return a * b
class TestMultiply(unittest.TestCase):
def test_positive_numbers(self):
self.assertEqual(multiply(2, 3), 6)
def test_zero(self):
self.assertEqual(multiply(5, 0), 0)
def test_negative_number(self):
self.assertEqual(multiply(-2, 3), -6)
if __name__ == "__main__":
unittest.main()
در این مثال سه حالت مختلف را آزمایش کردهایم.
نامگذاری تستها
متدهای تست باید با عبارت
test_
شروع شوند.
def test_add(self):
...
def test_subtract(self):
...
def test_login(self):
...
اگر نام متد با
test_
شروع نشود، unittest آن را بهعنوان تست شناسایی نمیکند.
متد setUp چیست؟
گاهی قبل از اجرای هر تست لازم است یک سری اطلاعات
یا اشیا را آماده کنیم.
برای این کار میتوانیم از
setUp()
استفاده کنیم.
import unittest
class TestUser(unittest.TestCase):
def setUp(self):
self.username = "ali"
def test_username(self):
self.assertEqual(self.username, "ali")
if __name__ == "__main__":
unittest.main()
متد
setUp()
قبل از اجرای هر تست اجرا میشود.
متد tearDown چیست؟
اگر بعد از اجرای تستها نیاز به انجام عملیات پاکسازی
داشته باشیم، میتوانیم از
tearDown()
استفاده کنیم.
import unittest
class TestExample(unittest.TestCase):
def setUp(self):
print("شروع تست")
def tearDown(self):
print("پایان تست")
def test_example(self):
self.assertEqual(1 + 1, 2)
if __name__ == "__main__":
unittest.main()
تست کردن خطاها با assertRaises
گاهی انتظار داریم یک تابع در شرایط خاص خطا ایجاد کند.
برای بررسی این حالت میتوانیم از
assertRaises()
استفاده کنیم.
import unittest
def divide(a, b):
return a / b
class TestDivide(unittest.TestCase):
def test_zero_division(self):
with self.assertRaises(ZeroDivisionError):
divide(10, 0)
if __name__ == "__main__":
unittest.main()
در این تست انتظار داریم تقسیم بر صفر باعث ایجاد
ZeroDivisionError
شود.
یک مثال کاربردی: بررسی سن کاربر
def is_adult(age):
return age >= 18
حالا برای این تابع چند تست مینویسیم:
import unittest
def is_adult(age):
return age >= 18
class TestIsAdult(unittest.TestCase):
def test_adult(self):
self.assertTrue(is_adult(20))
def test_not_adult(self):
self.assertFalse(is_adult(15))
def test_exactly_18(self):
self.assertTrue(is_adult(18))
if __name__ == "__main__":
unittest.main()
اجرای تستها در پایتون
فرض کنیم فایل تست ما نام زیر را دارد:
test_calculator.py
میتوانیم آن را مستقیماً اجرا کنیم:
python test_calculator.py
یا از قابلیت کشف خودکار تستها استفاده کنیم:
python -m unittest
خروجی موفق تست
اگر همه تستها با موفقیت اجرا شوند، معمولاً خروجی شبیه نمونه زیر خواهیم داشت:
...
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK
عبارت
OK
یعنی تستها با موفقیت اجرا شدهاند.
اگر یک تست شکست بخورد چه میشود؟
اگر نتیجه واقعی با نتیجه مورد انتظار متفاوت باشد، unittest تست را شکستخورده اعلام میکند.
self.assertEqual(2 + 2, 5)
در این حالت تست موفق نخواهد بود و جزئیات خطا نمایش داده میشود.
ساختار پیشنهادی پروژه
در پروژههای واقعی بهتر است کد اصلی و تستها ساختار مشخصی داشته باشند.
my_project/
│
├── calculator.py
│
└── test_calculator.py
فایل
calculator.py
شامل کد اصلی است و
test_calculator.py
تستهای آن را نگهداری میکند.
نکات مهم در تست نویسی
- تستها را کوتاه و مشخص بنویسید.
- هر تست بهتر است یک رفتار مشخص را بررسی کند.
- نام تست باید هدف آن را مشخص کند.
- حالتهای مختلف ورودی را بررسی کنید.
- فقط حالت موفق را تست نکنید؛ خطاها را نیز بررسی کنید.
- تستها را مرتب و قابل فهم نگه دارید.
unittest یا pytest؟
unittest
بخشی از کتابخانه استاندارد پایتون است و برای یادگیری
اصول تست نویسی گزینه مناسبی محسوب میشود.
در پروژههای پایتونی ابزارهای دیگری مانند
pytest
نیز بسیار مورد استفاده قرار میگیرند.
برای شروع بهتر است ابتدا مفاهیم پایه تست، assertion و ساختار تستها را یاد بگیریم و سپس سراغ ابزارهای پیشرفتهتر برویم.
تمرینهای تست نویسی
تمرین ۱
تابعی به نام
subtract(a, b)
بنویسید و برای آن حداقل سه تست ایجاد کنید.
تمرین ۲
تابعی بنویسید که مشخص کند یک عدد زوج است یا فرد، سپس برای آن تست بنویسید.
تمرین ۳
تابعی ایجاد کنید که یک لیست را دریافت کرده و بزرگترین عدد آن را برگرداند. سپس چند تست برای آن بنویسید.
تمرین ۴
تابع تقسیم را طوری تست کنید که مطمئن شوید تقسیم بر صفر
باعث ایجاد
ZeroDivisionError
میشود.
جمعبندی
تست نویسی یکی از مهارتهای مهم در برنامهنویسی پایتون است. با استفاده از تستها میتوانیم عملکرد قسمتهای مختلف برنامه را بررسی کنیم و احتمال ایجاد خطا را کاهش دهیم.
در این درس با مفاهیمی مانند
assert،
unittest،
TestCase،
setUp،
tearDown
و
assertRaises
آشنا شدیم.
در مراحل بعدی میتوانیم سراغ ابزارهای حرفهایتر
تست نویسی مانند
pytest
برویم.
سوالات متداول
تست نویسی در پایتون چیست؟
تست نویسی یعنی بررسی خودکار عملکرد بخشهای مختلف برنامه برای اطمینان از اینکه خروجی مورد انتظار را تولید میکنند.
آیا unittest نیاز به نصب دارد؟
خیر. unittest بخشی از کتابخانه استاندارد پایتون است و معمولاً نیازی به نصب جداگانه ندارد.
assert در پایتون چه کاری انجام میدهد؟
assert یک شرط را بررسی میکند و اگر شرط نادرست باشد، معمولاً خطای AssertionError ایجاد میکند.
آیا باید همه برنامه را تست کنیم؟
بهتر است قسمتهای مهم و حساس برنامه و رفتارهایی که احتمال خطا در آنها بیشتر است، با تستهای مناسب بررسی شوند.