如何用pytest全局Fixture最小化代码量Mock函数?
全局Mock函数的最简实现方案
核心要点
Python里mock函数的关键是patch被调用模块里的目标函数引用——也就是work.get_id,而非原定义的utils.get_id。用pytest的全局自动生效fixture,能做到一次定义、所有测试复用,彻底减少样板代码。
具体步骤
1. 编写全局Fixture(conftest.py)
在项目根目录的conftest.py里定义这个fixture,设置autouse=True让所有测试自动生效:
# conftest.py from unittest.mock import patch import pytest @pytest.fixture(autouse=True) def mock_get_id(): # 重点:patch work模块里的get_id引用 with patch('work.get_id') as mock: # 设置默认的mock返回值,按需修改 mock.return_value = "mocked_id_123" yield mock
2. 测试用例(tests/test_work.py)
现在测试里完全不用写重复的patch代码,直接验证逻辑即可:
# tests/test_work.py from work import do_work def test_do_work(): result = do_work() # 验证结果是否符合mock后的预期 assert result == "processed: mocked_id_123" # 可选:检查get_id的调用参数和次数 from work import get_id get_id.assert_called_once_with("default_param1", "default_param2")
3. 原模块参考代码
utils.py
# utils.py def get_id(param1, param2): # 原业务逻辑,比如调用外部接口生成真实ID return f"real_id_{param1}_{param2}"
work.py
# work.py from utils import get_id def do_work(): id = get_id("default_param1", "default_param2") return f"processed: {id}"
之前方案失效的原因
- 方案2中直接patch
utils.get_id没用:因为work.py已经把get_id的引用导入到自身模块里,patch原模块不会更新已导入的引用。 - monkeypatch方案如果没找对目标(应该修改
work.get_id而非utils.get_id),自然也无法生效。
扩展:个别测试自定义mock行为
要是某个测试需要不同的mock返回值,直接在测试里覆盖fixture的设置即可:
def test_do_work_custom_mock(mock_get_id): mock_get_id.return_value = "custom_mocked_id" result = do_work() assert result == "processed: custom_mocked_id"
内容的提问来源于stack exchange,提问作者Guillaume
相关产品推荐
相关产品推荐

