🛠️ 三、5 大实战场景(附完整代码)
场景 1:Mock 第三方 HTTP 请求(避免真实网络调用)
# payment.pyimport requestsdef process_payment(amount): resp = requests.post("https://payment-gateway.com/pay", json={"amount": amount}) return resp.json()["transaction_id"]# test_payment.pyfrom unittest.mock import patch@patch('payment.requests.post')def test_process_payment(mock_post): # 预设网关返回 mock_post.return_value.json.return_value = {"transaction_id": "txn_123"} txn_id = process_payment(100) assert txn_id == "txn_123" # 验证请求参数 mock_post.assert_called_once_with( "https://payment-gateway.com/pay", json={"amount": 100} )
场景 2:Stub 时间函数(让时间可控)
# report.pyfrom datetime import datetimedef generate_daily_report(): today = datetime.now().strftime("%Y-%m-%d") return f"Report for {today}"# test_report.pyfrom unittest.mock import patchfrom datetime import datetime@patch('report.datetime')def test_generate_daily_report(mock_datetime): # 固定当前时间为 2025-01-01 mock_datetime.now.return_value = datetime(2025, 1, 1) mock_datetime.strftime = lambda self, fmt: self.strftime(fmt) report = generate_daily_report() assert report == "Report for 2025-01-01"💡 技巧:Mock datetime 时需同时处理 now() 和 strftime。
场景 3:Mock 数据库连接(无需启动 DB)
# user_service.pyimport sqlite3def get_user(user_id): conn = sqlite3.connect("app.db") cursor = conn.cursor() cursor.execute("SELECT name FROM users WHERE id=?", (user_id,)) row = cursor.fetchone() conn.close() return row[0] if row else None# test_user_service.pyfrom unittest.mock import patch, MagicMock@patch('user_service.sqlite3')def test_get_user(mock_sqlite3): # 模拟数据库连接和游标 mock_conn = MagicMock() mock_cursor = MagicMock() mock_sqlite3.connect.return_value = mock_conn mock_conn.cursor.return_value = mock_cursor mock_cursor.fetchone.return_value = ("Alice",) name = get_user(1) assert name == "Alice" # 验证 SQL 是否正确执行 mock_cursor.execute.assert_called_once_with( "SELECT name FROM users WHERE id=?", (1,) )
场景 4:验证异常处理逻辑
# api_client.pyimport requestsdef fetch_user(user_id): try: resp = requests.get(f"https://api.example.com/users/{user_id}") resp.raise_for_status() return resp.json() except requests.RequestException: return {"error": "Network failed"}# test_api_client.pyfrom unittest.mock import patchimport requests@patch('api_client.requests.get')def test_fetch_user_network_error(mock_get): # 模拟网络异常 mock_get.side_effect = requests.RequestException("Timeout") result = fetch_user(123) assert result == {"error": "Network failed"}
✅ side_effect 可抛出异常、返回不同值序列,或执行自定义函数。
场景 5:Mock 类实例(替代 __init__)
# email_service.pyclass EmailClient: def __init__(self, api_key): self.api_key = api_key def send(self, to, subject): # 调用真实邮件服务 passdef notify_user(user_email): client = EmailClient("SECRET_KEY") client.send(user_email, "Welcome!")# test_email_service.pyfrom unittest.mock import patch@patch('email_service.EmailClient')def test_notify_user(mock_client_class): # mock_client_class 是类的 Mock mock_instance = mock_client_class.return_value # 实例的 Mock notify_user("alice@example.com") # 验证是否创建了实例 mock_client_class.assert_called_once_with("SECRET_KEY") # 验证实例方法是否被调用 mock_instance.send.assert_called_once_with("alice@example.com", "Welcome!")