ویرگول
ورودثبت نام
shayan hoseini
shayan hoseini
خواندن ۲ دقیقه·۶ سال پیش

تست کردن چیزی که قابل تست نیست با استفاده از Mock در Python

در هر برنامه ممکن است قسمتهایی وجود داشته باشند که برای عملکرد خود به API بیرونی نیاز دارند. مثلا فرض کنید قسمتی از برنامه به بات تلگرام وصل شده و پیامی را میفرستد، شما نباید این API را در تست خود داشته باشید زیرا هر بار که تست خود را اجرا میکنید اولا نیاز به اینترنت دارید و همچنین باید مقدار زمانی که طول میکشد تا سرور تلگرام جواب شما را بدهد برای پاس شدن تست معطل بمانید که هر دوی اینها منطقی نیست.

برای اینکار کتابخانه Mock در پایتون به شما امکان میدهد تا با استفاده از آن رفتار شی ای دیگر را شبیه سازی کنید. برای استفاده از این کتابخانه آنرا بوسیله pip install mock نصب کنید. حال با چیزی شبیه ‍‍Python Shell یا ‍‍‍‍‍ipython دستور زیر را راجرا کنید تا کمی بیشتر با عملکرد آن آشنا شوید.

from unittest import mock m = mock.Mock()

تا اینجا یک نمونه از Mock ساختیم و برای اینکه بدانیم این شی چه امکاناتی به ما میدهد:

dir(m)

و خروجی کل attribute های این شی است:

['assert_any_call', 'assert_called_once_with', 'assert_called_with', 'assert_has_calls', 'attach_mock', 'call_args', 'call_args_list', 'call_count', 'called', 'configure_mock', 'method_calls', 'mock_add_spec', 'mock_calls', 'reset_mock', 'return_value', 'side_effect']

ولی امکان جالب و دور از انتظار این است که شما میتوانید از attribute هایی که برای این شی تعریف نشده هم استفاده کنید و خروجی همان قبلی خواهد بود:

dir(m.some_attribute)

عموما برای تست ها میخواهیم بدانیم متد مورد نظر صدا زده میشود(call) یا خیر. مثلا همینکه بدانیم کلاس Telegram متدی به نام Send دارد و آن نیز در اینجا صدا زده شده کافی است. برای اینکار از خاصیت assert_called_with میتوانید استفاده کنید. اما برای شروع میتوانیم تستی بنویسیم که متد مورد نظر یک خروجی شبیه چیزی که تلگرام به ما میدهد را برگرداند.

from unittest import TestCase from unittest.mock import Mock ​ ​ class TestTelegram(TestCase): def test_send_telegram_message(self): MockTelegram = Mock() MockTelegram.send.return_value = [ { 'id': 100121, 'text': 'Test Title' } ] response = MockTelegram.send() self.assertIsNotNone(response) self.assertIsInstance(response[0], dict)

تا اینجا متدی از تلگرام که حتی آنرا ننوشته ایم را تست میکنیم که متد send آن دارای خروجی شبیه return_value است. شما احتمالا میخواهید بدانید اگر سرور تلگرام در واقعیت جواب نمیداد و سیستم ما به آن دسترسی نداشت را چگونه تست کنیم. برای این کار از side_effect استفاده کنید.

from unittest import TestCase from unittest.mock import Mock ​ class TestTelegram(TestCase): def test_does_not_send_telegram_message(self): MockBlog = Mock() MockBlog.send.side_effect = Exception('Telegram Unreachable') with self.assertRaises(Exception): MockBlog.send()

در این تست در واقع میخواهیم منتظر باشیم تا اگر تلگرام پاسخ نداد متد ‍‍‍send اکسپشن بدهد.

pythonmockunittestتست
back-end developer
شاید از این پست‌ها خوشتان بیاید