Testing و Debugging 🧪
یاد میگیریم چطور کدهامون رو تست کنیم و باگها رو شکار کنیم!
🧪 Unit Testing: تست کردن قطعه به قطعه
Unit Testing یعنی اینکه هر تابع و کلاس رو جداگانه تست کنیم تا مطمئن بشیم درست کار میکنن. پایتون یه ماژول داخلی به اسم `unittest` داره که خیلی قدرتمنده!
import unittest
# کلاسی که میخوایم تستش کنیم
class Calculator:
def add(self, a, b):
return a + b
def divide(self, a, b):
if b == 0:
raise ValueError("تقسیم بر صفر مجاز نیست!")
return a / b
def is_even(self, number):
return number % 2 == 0
# کلاس تست
class TestCalculator(unittest.TestCase):
def setUp(self):
"""این متد قبل از هر تست اجرا میشه"""
self.calc = Calculator()
def test_add_positive_numbers(self):
"""تست جمع اعداد مثبت"""
result = self.calc.add(2, 3)
self.assertEqual(result, 5)
def test_add_negative_numbers(self):
"""تست جمع اعداد منفی"""
result = self.calc.add(-2, -3)
self.assertEqual(result, -5)
def test_divide_normal(self):
"""تست تقسیم عادی"""
result = self.calc.divide(10, 2)
self.assertEqual(result, 5.0)
def test_divide_by_zero(self):
"""تست تقسیم بر صفر - باید خطا بده"""
with self.assertRaises(ValueError):
self.calc.divide(10, 0)
def test_is_even(self):
"""تست تشخیص عدد زوج"""
self.assertTrue(self.calc.is_even(4))
self.assertFalse(self.calc.is_even(5))
# اجرای تستها
if __name__ == '__main__':
unittest.main()
# خروجی:
# .....
# ----------------------------------------------------------------------
# Ran 5 tests in 0.001s
#
# OK
دیباگینگ: شکار باگها! 🐛
دیباگینگ یعنی پیدا کردن و رفع کردن باگها. پایتون ابزارهای قدرتمندی برای این کار داره:
- print() debugging: سادهترین روش برای دیدن مقادیر متغیرها
- pdb debugger: دیباگر داخلی پایتون برای کنترل دقیق اجرای کد
- logging: ثبت اطلاعات مفصل برای تحلیل بعدی
import pdb
import logging
# تنظیم logging
logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s')
def divide_numbers(a, b):
logging.debug(f"شروع تقسیم {a} بر {b}")
# نقطه توقف برای دیباگ
pdb.set_trace()
if b == 0:
logging.error("تقسیم بر صفر!")
raise ValueError("نمیتوان بر صفر تقسیم کرد")
result = a / b
logging.info(f"نتیجه: {result}")
return result
# تست
try:
result = divide_numbers(10, 2)
print(f"نتیجه: {result}")
except ValueError as e:
print(f"خطا: {e}")
تستهای پیشرفته: pytest و Mock
pytest یکی از محبوبترین کتابخانههای تست پایتون هست. Mock هم برای شبیهسازی اجزای خارجی استفاده میشه:
import pytest
from unittest.mock import Mock, patch
import requests
# کلاس برای تست
class WeatherAPI:
def get_temperature(self, city):
response = requests.get(f"http://api.weather.com/{city}")
return response.json()['temperature']
# تست با pytest
def test_calculator_add():
calc = Calculator()
assert calc.add(2, 3) == 5
assert calc.add(-1, 1) == 0
def test_calculator_divide_by_zero():
calc = Calculator()
with pytest.raises(ValueError):
calc.divide(10, 0)
# تست با Mock
@patch('requests.get')
def test_weather_api(mock_get):
# شبیهسازی پاسخ API
mock_response = Mock()
mock_response.json.return_value = {'temperature': 25}
mock_get.return_value = mock_response
weather = WeatherAPI()
temp = weather.get_temperature('Tehran')
assert temp == 25
mock_get.assert_called_once_with('http://api.weather.com/Tehran')
# اجرای تستها:
# pytest test_file.py -v
تمرین! 🧠
یه کلاس `BankAccount` بنویس که متدهای `deposit`, `withdraw` و `get_balance` داشته باشه. بعد برای این کلاس تستهای کامل بنویس که شامل تست موجودی اولیه، واریز پول، برداشت پول و برداشت بیش از موجودی (که باید خطا بده) باشه. از unittest استفاده کن.
جواب تمرین
import unittest
class BankAccount:
def __init__(self, initial_balance=0):
self.balance = initial_balance
def deposit(self, amount):
if amount <= 0:
raise ValueError("مبلغ باید مثبت باشد")
self.balance += amount
return self.balance
def withdraw(self, amount):
if amount <= 0:
raise ValueError("مبلغ باید مثبت باشد")
if amount > self.balance:
raise ValueError("موجودی کافی نیست")
self.balance -= amount
return self.balance
def get_balance(self):
return self.balance
class TestBankAccount(unittest.TestCase):
def setUp(self):
self.account = BankAccount(100)
def test_initial_balance(self):
self.assertEqual(self.account.get_balance(), 100)
def test_deposit(self):
self.account.deposit(50)
self.assertEqual(self.account.get_balance(), 150)
def test_withdraw(self):
self.account.withdraw(30)
self.assertEqual(self.account.get_balance(), 70)
def test_withdraw_insufficient_funds(self):
with self.assertRaises(ValueError):
self.account.withdraw(200)
def test_negative_deposit(self):
with self.assertRaises(ValueError):
self.account.deposit(-10)
if __name__ == '__main__':
unittest.main()
چالش پیشرفته! 🚀
یه سیستم تست کامل برای یه فروشگاه آنلاین بساز که شامل کلاسهای Product, Cart و Order باشه. تستهات باید شامل اضافه کردن محصول به سبد، محاسبه قیمت کل، اعمال تخفیف و پردازش سفارش باشه. از Mock برای شبیهسازی پرداخت آنلاین استفاده کن!