ویژگی تصویر

کتابخانه unittest در پایتون

  /  پایتون   /  کتابخانه unittest در پایتون
بنر تبلیغاتی الف

کتابخانه unittest یکی از ابزارهای داخلی پایتون برای انجام تست واحد (Unit Testing) است. این کتابخانه به برنامه‌نویسان کمک می‌کند تا بخش‌های مختلف کد خود را به‌صورت جداگانه تست کرده و از صحت عملکرد آن‌ها اطمینان حاصل کنند. هدف تست واحد، یافتن خطاهای منطقی در بخش‌های کوچک‌تر برنامه، قبل از ترکیب آن‌ها در یک سیستم بزرگ‌تر است.

مفهوم تست واحد (Unit Test)

تست واحد به معنای بررسی رفتار صحیح هر تابع یا کلاس به‌صورت مستقل است. در پایتون، با استفاده از unittest می‌توان مجموعه‌ای از تست‌ها را تعریف کرد تا پس از هر تغییر در کد، به‌صورت خودکار اجرا شوند و نتیجه را گزارش دهند.

مزایای استفاده از تست واحد

  • افزایش پایداری و کیفیت کد
  • شناسایی سریع خطاها قبل از انتشار نرم‌افزار
  • امکان Refactor کردن کد با اطمینان بیشتر
  • صرفه‌جویی در زمان اشکال‌زدایی (Debugging)

شروع کار با unittest

برای شروع، کافی است ماژول unittest را در پروژه‌ی خود وارد (import) کرده و یک کلاس جدید برای تست‌ها ایجاد کنید. هر متد تست باید با پیشوند test_ شروع شود تا توسط چارچوب تست شناسایی شود.

import unittest

def add(a, b):
    return a + b

class TestMathFunctions(unittest.TestCase):

    def test_addition(self):
        result = add(2, 3)
        self.assertEqual(result, 5)

if __name__ == '__main__':
    unittest.main()

در این مثال، تابع add تست می‌شود تا بررسی گردد که جمع دو عدد به درستی انجام می‌شود. تابع assertEqual یکی از متدهای پرکاربرد برای مقایسه‌ی مقدار واقعی با مقدار مورد انتظار است.

ساختار کلاس‌های تست در unittest

هر کلاس تست باید از unittest.TestCase ارث‌بری کند. این کلاس شامل مجموعه‌ای از متدها برای بررسی شرایط مختلف است.

متدهای پرکاربرد در unittest

متدتوضیح
assertEqual(a, b)بررسی می‌کند که دو مقدار برابر باشند.
assertNotEqual(a, b)بررسی می‌کند که دو مقدار برابر نباشند.
assertTrue(x)بررسی می‌کند که مقدار x برابر True باشد.
assertFalse(x)بررسی می‌کند که مقدار x برابر False باشد.
assertIsNone(x)بررسی می‌کند که x برابر None باشد.
assertIn(a, b)بررسی می‌کند که مقدار a در b وجود داشته باشد.

مثال پیشرفته‌تر با متدهای setUp و tearDown

متدهای setUp() و tearDown() برای آماده‌سازی و پاک‌سازی محیط تست قبل و بعد از هر تست استفاده می‌شوند.

import unittest

class TestListMethods(unittest.TestCase):

    def setUp(self):
        self.my_list = [1, 2, 3]

    def tearDown(self):
        self.my_list.clear()

    def test_append(self):
        self.my_list.append(4)
        self.assertIn(4, self.my_list)

    def test_remove(self):
        self.my_list.remove(2)
        self.assertNotIn(2, self.my_list)

if __name__ == '__main__':
    unittest.main()

در اینجا قبل از اجرای هر تست، لیست my_list مقداردهی اولیه می‌شود و بعد از هر تست پاک می‌گردد. این روش باعث می‌شود تست‌ها از یکدیگر مستقل باشند.

استفاده از skip و expectedFailure

در بعضی شرایط، ممکن است بخواهید تستی را به‌صورت موقت نادیده بگیرید یا تستی را به‌عنوان شکست‌خورده‌ی مورد انتظار علامت‌گذاری کنید.

import unittest

class TestFeatures(unittest.TestCase):

    @unittest.skip("این تست موقتاً غیرفعال است")
    def test_future_feature(self):
        self.assertEqual(1, 2)

    @unittest.expectedFailure
    def test_known_bug(self):
        self.assertEqual(10 / 0, 5)

if __name__ == '__main__':
    unittest.main()

در این مثال، تست اول نادیده گرفته می‌شود و تست دوم به‌عنوان خطای پیش‌بینی‌شده اجرا می‌شود، بدون اینکه شکست در نتیجه‌ی نهایی ثبت شود.

تست استثناها (Exceptions)

یکی از جنبه‌های مهم در تست‌نویسی، اطمینان از نحوه‌ی مدیریت خطاها است. می‌توان با استفاده از assertRaises بررسی کرد که آیا کد مورد انتظار خطای مشخصی را ایجاد می‌کند یا خیر.

import unittest

def divide(a, b):
    return a / b

class TestExceptions(unittest.TestCase):

    def test_zero_division(self):
        with self.assertRaises(ZeroDivisionError):
            divide(10, 0)

if __name__ == '__main__':
    unittest.main()

در اینجا، اگر تابع divide در هنگام تقسیم بر صفر خطای ZeroDivisionError ایجاد کند، تست موفق خواهد بود.

گروه‌بندی و اجرای مجموعه تست‌ها (Test Suites)

برای پروژه‌های بزرگ، بهتر است تست‌ها را در قالب فایل‌ها و ماژول‌های جداگانه سازمان‌دهی کنید. سپس می‌توان آن‌ها را در قالب یک مجموعه (Suite) ترکیب و با هم اجرا کرد.

import unittest
from test_math import TestMathFunctions
from test_strings import TestStringMethods

if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(unittest.makeSuite(TestMathFunctions))
    suite.addTest(unittest.makeSuite(TestStringMethods))
    runner = unittest.TextTestRunner()
    runner.run(suite)

به کمک TestSuite می‌توانید چندین کلاس تست را در یکجا اجرا کنید. این ویژگی در پروژه‌های بزرگ و چندبخشی بسیار کاربردی است.

نکات و بهترین شیوه‌ها (Best Practices)

  • نام‌گذاری تست‌ها را توصیفی انتخاب کنید (مثلاً test_addition_of_two_numbers).
  • هر تست باید فقط یک رفتار خاص را بررسی کند.
  • از داده‌های تست کوچک و ساده استفاده کنید تا خطایابی راحت‌تر شود.
  • خروجی تست‌ها را خودکار کنید و در فرآیند CI/CD پروژه قرار دهید.
  • از متد setUpClass و tearDownClass برای آماده‌سازی داده‌های عمومی استفاده کنید.

اجرای تست‌ها از طریق خط فرمان

برای اجرای تست‌ها در خط فرمان، کافی است دستور زیر را اجرا کنید:

python -m unittest discover

این دستور تمام فایل‌هایی که با test_ شروع می‌شوند را به‌صورت خودکار پیدا و اجرا می‌کند. گزینه‌ی discover یکی از ابزارهای قدرتمند برای اجرای گروهی تست‌ها در پروژه‌های بزرگ است.

مقایسه unittest با سایر فریم‌ورک‌ها

ویژگیunittestpytest
پشتیبانی پیش‌فرض در پایتونبلهخیر (نیاز به نصب دارد)
سینتکس ساده‌ترنسبتاً پیچیده‌ترساده‌تر و کوتاه‌تر
گزارش خروجی خوانامتوسطپیشرفته‌تر
قابلیت افزونه‌نویسیمحدودزیاد

با وجود اینکه pytest امکانات پیشرفته‌تری دارد، اما unittest به دلیل داخلی بودن در پایتون و قابلیت اطمینان بالا، همچنان یکی از گزینه‌های اصلی در تست‌نویسی محسوب می‌شود.

جمع‌بندی

کتابخانه unittest پایه‌ای‌ترین و رسمی‌ترین ابزار تست در پایتون است که امکان تست خودکار، بررسی استثناها و سازمان‌دهی تست‌ها را به شکلی ساخت‌یافته فراهم می‌کند. یادگیری این کتابخانه برای هر برنامه‌نویس حرفه‌ای پایتون ضروری است و پایه‌ای قوی برای ورود به ابزارهای پیشرفته‌تر مانند pytest و nose فراهم می‌آورد.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: