0Pricing
Python Academy · บทเรียน

การจำลองด้วย unittest.mock

แยกหน่วยที่อยู่ระหว่างการทดสอบด้วยการจำลองการพึ่งพา

การจำลองด้วย unittest.mock เป็นบทเรียน Python Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Python Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Python Academy มีบทเรียนทั้งหมด 4 บทเรียน

เหตุใดจึงใช้ม็อก

ม็อกจะแทนที่สิ่งที่โค้ดพึ่งพาจริง เช่น ฐานข้อมูล 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 จะกำหนดค่าเมธอดพิเศษหรือเมธอด 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 มีฟิกซ์เจอร์ 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 เพื่อทำม็อกฟังก์ชันแบบอะซิงโครนัสที่มีการรอผลด้วย await

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” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Python Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Python Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การจำลองด้วย unittest.mock”

แยกหน่วยที่อยู่ระหว่างการทดสอบด้วยการจำลองการพึ่งพา คุณปฏิบัติ Python Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Python Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Python Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การจำลองด้วย unittest.mock” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Python Academy นี้ได้ไหม

ได้ บทเรียน Python Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การเขียนการทดสอบ pytest แรกของคุณ
  2. ฟิกซ์เจอร์และการตั้งค่า/การรื้อถอน
  3. การกำหนดพารามิเตอร์และความครอบคลุมการทดสอบ
  4. การจำลองด้วย unittest.mock
← กลับไปที่ Python Academy