المحاكاة باستخدام unittest.mock
اعزل الوحدات قيد الاختبار بمحاكاة الاعتماديات
المحاكاة باستخدام unittest.mock درس مجاني في Python Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Python Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Python Academy 4 دروس في المجموع.
لماذا نستخدم Mock؟
تستبدل المحاكيات الاعتماديات الحقيقية، مثل قواعد البيانات وواجهات API ونظام الملفات، ببدائل يمكن التحكم فيها، حتى تعمل الاختبارات بسرعة وبشكل حتمي ومعزول.
from unittest.mock import Mock
api = Mock()
api.get_user.return_value = {"id": 1, "name": "Alice"}
result = api.get_user(1)
print(result) # {'id': 1, 'name': 'Alice'}Mock وMagicMock
يُعد Mock الفئة الأساسية. أما MagicMock فيضبط أساليب magic/dunder تلقائيًا، ولذلك يمكن استخدامه كعدادات أو مديري سياق وغير ذلك.
from unittest.mock import MagicMock
m = MagicMock()
m.__len__.return_value = 5
print(len(m)) # 5
m.__iter__.return_value = iter([1, 2, 3])
for x in m:
print(x)patch كمزيّن
استخدموا @patch لاستبدال كائن في وحدة برمجية بمحاكٍ طوال مدة الاختبار.
from unittest.mock import patch
def get_data():
import requests
return requests.get("https://api.example.com").json()
@patch("requests.get")
def test_get_data(mock_get):
mock_get.return_value.json.return_value = {"key": "value"}
result = get_data()
assert result == {"key": "value"}patch كمدير سياق
استخدموا patch() كمدير سياق لإجراء محاكاة أكثر محدودية في النطاق.
from unittest.mock import patch
def test_open():
with patch("builtins.open", create=True) as mock_open:
mock_open.return_value.__enter__.return_value.read.return_value = "data"
with open("file.txt") as f:
assert f.read() == "data"patch.object
يُجري patch.object(target, attribute) تصحيحًا لسمة محددة في كائن أو فئة موجودة.
from unittest.mock import patch
import mymodule
def test_method():
with patch.object(mymodule.MyClass, "fetch", return_value=42):
obj = mymodule.MyClass()
assert obj.fetch() == 42التحقق من الاستدعاءات
تسجّل المحاكيات كل استدعاء. استخدموا assert_called_once_with وassert_called_with وcall_count للتحقق من السلوك.
from unittest.mock import Mock
send = Mock()
send("hello", to="alice")
send.assert_called_once_with("hello", to="alice")
print(send.call_count) # 1return_value وside_effect
اضبطوا return_value للتحكم في القيمة التي يعيدها المحاكي. واستخدموا side_effect لإثارة الاستثناءات أو إعادة قيم مختلفة في الاستدعاءات المتتالية.
from unittest.mock import Mock
m = Mock(side_effect=[1, 2, ValueError("done")])
print(m()) # 1
print(m()) # 2
m() # raises ValueErrorspec: محاكيات آمنة النوع
مرّروا spec=MyClass لتقييد المحاكي بالسمات الموجودة فقط في الفئة الحقيقية.
from unittest.mock import Mock
class Calc:
def add(self, a, b): return a + b
m = Mock(spec=Calc)
m.add(1, 2) # OK
# m.subtract(1, 2) # AttributeError: Mock does not have 'subtract'patch.dict
استخدموا patch.dict لتعديل قاموس مؤقتًا، مثل متغيرات البيئة أو إعدادات مستوى الوحدة البرمجية.
from unittest.mock import patch
import os
def test_env():
with patch.dict(os.environ, {"DEBUG": "true"}):
assert os.environ["DEBUG"] == "true"
assert "DEBUG" not in os.environالمحاكاة في pytest باستخدام pytest-mock
يوفّر pytest-mock fixture باسم mocker يغلّف unittest.mock وينفّذ التنظيف تلقائيًا بعد كل اختبار.
# pip install pytest-mock
def test_service(mocker):
mocker.patch("mymodule.requests.get", return_value=mocker.Mock(
json=lambda: {"status": "ok"}
))
from mymodule import call_api
assert call_api()["status"] == "ok"AsyncMock للمهام غير المتزامنة
استخدموا AsyncMock لمحاكاة الدوال غير المتزامنة التي يجري انتظارها.
from unittest.mock import AsyncMock, patch
import asyncio
async def fetch():
import httpx
async with httpx.AsyncClient() as c:
r = await c.get("https://example.com")
return r.json()
def test_fetch():
with patch("httpx.AsyncClient.get", new_callable=AsyncMock) as m:
m.return_value.json.return_value = {"ok": True}
result = asyncio.run(fetch())
assert result["ok"] is Trueتحقّق سريع
ما السمة التي تضبطونها في Mock للتحكم في القيمة التي يعيدها عند استدعائه؟
مراجعة
توفّر unittest.mock كائنات Mock وMagicMock وpatch وAsyncMock. استخدموا return_value وside_effect للتحكم في السلوك، واستخدموا أساليب التأكيد للتحقق من كيفية استدعاء المحاكيات.
الأسئلة الشائعة
هل درس «المحاكاة باستخدام unittest.mock» مجاني؟
نعم — نص درس «المحاكاة باستخدام unittest.mock» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Python Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Python Academy 4 دروس في المجموع.
ماذا ستتعلم في «المحاكاة باستخدام unittest.mock»؟
اعزل الوحدات قيد الاختبار بمحاكاة الاعتماديات تتمرن على Python Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Python Academy؟
لا تُشترط خبرة سابقة. Python Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «المحاكاة باستخدام unittest.mock»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Python Academy هذا؟
نعم. كل درس في Python Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- كتابة اختبارات pytest الأولى
- التركيبات والإعداد/التنظيف
- تعدد المعاملات وتغطية الاختبارات
- المحاكاة باستخدام unittest.mock