การจำลองด้วย 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) # 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 มีฟิกซ์เจอร์ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การเขียนการทดสอบ pytest แรกของคุณ
- ฟิกซ์เจอร์และการตั้งค่า/การรื้อถอน
- การกำหนดพารามิเตอร์และความครอบคลุมการทดสอบ
- การจำลองด้วย unittest.mock