Mocking trong pytest: test code phụ thuộc mạng và database

Hàm của bạn gọi API thật thì test sẽ chậm, phụ thuộc mạng và có thể tốn tiền. Mocking cho phép thay thành phần bên ngoài bằng một bản giả có hành vi do bạn quy định.

Vấn đề

# thoi_tiet.py
import requests

def nhiet_do(thanh_pho):
    r = requests.get(f"https://api.example.com/weather/{thanh_pho}", timeout=10)
    return r.json()["temp"]

Mock bằng monkeypatch

# test_thoi_tiet.py
import thoi_tiet

class PhanHoiGia:
    def json(self):
        return {"temp": 31}

def test_nhiet_do(monkeypatch):
    def get_gia(url, timeout=None):
        return PhanHoiGia()

    monkeypatch.setattr(thoi_tiet.requests, "get", get_gia)
    assert thoi_tiet.nhiet_do("hanoi") == 31

monkeypatch tự động khôi phục nguyên trạng sau mỗi test — không rò rỉ sang test khác.

Dùng unittest.mock để kiểm tra cả cách gọi

from unittest.mock import patch, MagicMock

@patch("thoi_tiet.requests.get")
def test_goi_dung_url(mock_get):
    mock_get.return_value = MagicMock(**{"json.return_value": {"temp": 25}})

    assert thoi_tiet.nhiet_do("hue") == 25
    mock_get.assert_called_once()
    assert "hue" in mock_get.call_args[0][0]

Quy tắc vàng: vá ở nơi sử dụng

# Đúng: vá tên mà module của bạn nhìn thấy
@patch("thoi_tiet.requests.get")

# Sai: vá tận gốc, module đã import tham chiếu cũ rồi
@patch("requests.get")

Đây là lỗi khiến nhiều người mất hàng giờ. Hãy luôn vá theo đường dẫn trong module đang test.

Giả lập lỗi để test đường thất bại

import pytest, requests

@patch("thoi_tiet.requests.get", side_effect=requests.Timeout)
def test_khi_timeout(mock_get):
    with pytest.raises(requests.Timeout):
        thoi_tiet.nhiet_do("danang")

Fixture dùng lại nhiều nơi

import pytest

@pytest.fixture
def db_gia():
    du_lieu = {}
    yield du_lieu
    du_lieu.clear()     # dọn dẹp sau test

def test_luu(db_gia):
    db_gia["k"] = 1
    assert db_gia["k"] == 1

Đừng mock quá tay

Mock mọi thứ sẽ cho bạn bộ test luôn xanh nhưng chẳng chứng minh được gì. Nguyên tắc: chỉ mock những gì vượt ra khỏi ranh giới chương trình — mạng, thời gian, hệ thống file, dịch vụ trả phí. Logic của chính bạn thì hãy test thật.

Lên đầu trang