0Pricing
Python Academy · درس

المحاكاة باستخدام 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)  # 1

return_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 ValueError

spec: محاكيات آمنة النوع

مرّروا 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 يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. كتابة اختبارات pytest الأولى
  2. التركيبات والإعداد/التنظيف
  3. تعدد المعاملات وتغطية الاختبارات
  4. المحاكاة باستخدام unittest.mock
← العودة إلى Python Academy