برنامه نویسی

نحوه تست کد پایتون با استفاده از ماژول 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() عملکرد برای دریافت خروجی دقیق از آزمون.

خروجی با استفاده از پرچم -v

روش های متداول مورد استفاده برای ادعا

در اینجا فهرستی از متداول‌ترین روش‌های ادعایی مورد استفاده در تست واحد آورده شده است.

روش آن را بررسی می کند
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 بحث و جدل.

خروجی TestTriangle

آزمون استثنایی

اگر قبلاً از عبارات 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() تابع با یک آرگومان معتبر ارسال می شود.

خروجی OddTestCase

روش تست بالا شکست خورد و باعث شد یک 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() حذف می شود، در غیر این صورت، آزمون اجرا می شود.

خروجی slipIf

شکست مورد انتظار

اگر یک روش تست یا کلاس تست با شرایطی داریم که انتظار می رود نادرست باشد، می توانیم از آن استفاده کنیم 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 در پایتون فایل ها و دایرکتوری های موقت تولید کنیم؟


✅یک مدل یادگیری عمیق سفارشی با استفاده از تکنیک آموزش انتقال بسازید.

فعلاً همین است

به کدنویسی ادامه دهید✌✌

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا