如何用Python的Monkeypatch实现类似Mock Side Effect的多返回值功能?
用Python Monkeypatch实现函数多次调用返回不同值
要实现Monkeypatch后让retrieve_files两次调用返回不同值,核心思路是给原函数替换一个能维护调用状态的自定义函数,以此模拟Mock中side_effect的效果,下面是两种简单直接的实现方式:
方法1:用迭代器生成固定返回序列
适合提前确定所有返回值的场景,逻辑简洁,和Mock的side_effect列表行为一致:
import pytest from your_module import retrieve_files # 替换成实际包含retrieve_files的模块路径 def test_retrieve_files_twice(monkeypatch): # 定义两次调用要返回的不同结果 return_values = ["dir1_file_list", "dir2_file_list"] # 转成迭代器,每次调用取一个值 value_iterator = iter(return_values) # 定义替换函数 def mock_retrieve_files(): return next(value_iterator) # 执行Monkeypatch替换原函数 monkeypatch.setattr("your_module.retrieve_files", mock_retrieve_files) # 验证两次调用结果 assert retrieve_files() == "dir1_file_list" assert retrieve_files() == "dir2_file_list"
如果调用次数超过迭代器长度,会抛出StopIteration异常,和Mock使用列表作为side_effect的行为完全一致。
方法2:用闭包维护调用计数
适合需要根据调用次数做复杂逻辑判断的场景,比如不同次数返回不同类型数据、模拟错误:
import pytest from your_module import retrieve_files def test_retrieve_files_with_counter(monkeypatch): call_count = 0 def mock_retrieve_files(): nonlocal call_count call_count += 1 if call_count == 1: return ["file1.txt", "file2.jpg"] elif call_count == 2: return ["report.pdf", "data.csv"] # 超过调用次数可按需处理,比如抛出异常或返回默认值 raise ValueError("Unexpected third call") monkeypatch.setattr("your_module.retrieve_files", mock_retrieve_files) assert retrieve_files() == ["file1.txt", "file2.jpg"] assert retrieve_files() == ["report.pdf", "data.csv"]
非pytest环境的通用逻辑
如果不是用pytest的monkeypatch fixture,而是自己手动实现Monkeypatch(比如直接替换模块属性),核心逻辑完全相同——只要把原函数替换成一个能跟踪调用状态的自定义函数即可,状态可以用闭包、类实例或者全局变量维护。
内容的提问来源于stack exchange,提问作者Nitin Varghese
相关产品推荐
相关产品推荐

