如何正确Mock类实例调用的外部函数?pytest单元测试求助
编写单元测试时,在test_model.py中定义TestPlayerAnomalyDetectionModel类,实例化PlayerAnomalyDetectionModel后调用.fit方法。该方法内部会调用发送API请求的get_player_account_status函数,需要Mock这个函数并通过side_effect返回不同值,但尝试两种patch路径都未生效,实际API请求仍被触发:
- 使用
@mock.patch('get_player_labels.get_player_account_status'),Mock未生效 - 改用
@mock.patch('model.get_player_account_status'),实际函数仍被调用
1. 确认Patch的正确路径
你的核心思路是对的:必须Patch函数被调用位置的引用。model.py中通过from get_player_labels import get_player_account_status导入函数,因此Patch路径'model.get_player_account_status'是正确的,但需要排查模块导入冲突问题:
- 测试文件中同时导入了
import mock和from unittest.mock import patch,容易导致模块混淆,建议删除import mock,统一使用unittest.mock下的patch装饰器。
2. 修正Mock的使用逻辑
你当前的side_effect用法有误:get_player_account_status本身没有返回值,它是通过修改传入的account_statuses字典来完成状态设置的,直接给side_effect传字符串列表不会产生预期效果。
正确的Mock方式是模拟函数的行为,直接修改传入的字典参数:
from unittest.mock import patch # ... 其他代码保持不变 @patch('model.get_player_account_status') def test_fit(self, mock_get_player_account_status): # 定义要依次返回的状态列表 status_sequence = [ 'open', 'open', 'tosViolation', 'tosViolation', 'tosViolation', 'closed', 'open', 'open', 'tosViolation', 'tosViolation', 'tosViolation', 'closed', ] # 模拟函数行为:修改传入的account_statuses字典 def mock_set_account_status(player, account_statuses): account_statuses[player] = status_sequence.pop(0) mock_get_player_account_status.side_effect = mock_set_account_status self.model.fit(self.sample_train_data, generate_plots=False) # 可选:验证Mock被调用的次数是否符合预期 self.assertEqual(mock_get_player_account_status.call_count, 12)
3. 排查实例化时机问题
确保PlayerAnomalyDetectionModel实例是在Patch生效之后创建的:你的setUp方法在测试方法之前执行,而patch装饰器会包裹整个测试方法,因此实例化顺序是正确的。如果有其他fixture提前创建了模型实例,会导致Mock失效,需要检查fixture的执行顺序。
4. 调试Mock是否生效的技巧
在测试方法中添加打印,确认Mock对象是否被正确注入:
@patch('model.get_player_account_status') def test_fit(self, mock_get_player_account_status): # 打印Mock对象,若输出类似<MagicMock name='get_player_account_status' id='xxxx'>则说明注入成功 print(mock_get_player_account_status) # 后续测试代码...
如果输出原始函数对象,说明Patch路径错误或时机不对。
内容的提问来源于stack exchange,提问作者Derek O

