本文详解如何在 python 单元测试中精准 mock 被类方法内部调用的外部函数(如 `get_player_account_status`),重点解决路径指定错误、作用域不匹配及 `side_effect` 动态返回等常见问题,并提供可复现的修复方案。
在测试 PlayerAnomalyDetectionModel.fit() 时,你遇到的核心问题并非 side_effect 使用不当,而是 mock 路径错误——这是 unittest.mock.patch 最常见的陷阱。关键原则是:必须 patch 函数被“导入并使用”的位置,而非其“定义位置”。
回顾你的代码结构:
✅ 正确 patch 路径应为:'model.get_player_account_status'
❌ 错误路径(导致 mock 失效):'get_player_labels.get_player_account_status' 或 'model.get_player_labels.get_player_account_status'
此外,你的测试类混合了 pytest fixture 和 unittest.TestCase,存在兼容性风险(@mock.patch 装饰器对 unittest.TestCase 子类有效,但 @pytest.fixture(autouse=True) 在 unittest 类中行为不可靠)。建议统一风格,推荐纯 pytest 方案(更简洁、无继承冲突):
import pandas as pd
import pytest
from unittest.mock import patch
from model import PlayerAnomalyDetectionModel
@pytest.fixture
def sample_train_data():
# 构造示例数据(此处省略具体实现)
return pd.DataFrame({"player": ["p1", "p2", "p3"], "score": [1.0, 2.0, 3.0]})
# 使用 pytest 风格:直接 patch model 模块中的函数
def test_fit_with_mocked_account_status(sample_train_data):
model = PlayerAnomalyDetectionModel()
# 指定正确的 patch 路径:model 模块内导入的函数名
with patch('model.get_player_account_status') as mock_get_status:
# 配置 side_effect 实现每次调用返回不同值
mock_get_status.side_effect = [
'open', 'open', 'tosViolation', 'tosViolation', 'tosViolation', 'closed',
'open', 'open', 'tosViolation', 'tosViolation', 'tosViolation', 'closed'
]
# 执行被测方法
model.fit(sample_train_data, generate_plots=False)
# 断言 mock 被调用(可选验证)
assert mock_get_status.call_count == 12 # 根据实际逻辑调整预期次数正确 mock 的三要素:
遵循以上原则,即可稳定拦截类内部的外部函数调用,彻底避免真实 API 请求,构建健壮、快速、可重复的单元测试。