pytest中如何对同一方法的不同调用设置不同monkey patch
实现方案
完全可以实现该需求,不需要对同一个add()方法打两份独立的monkey patch,后打的patch会覆盖前序patch,最终只会生效最后一个。正确的实现思路是通过单份patch接管add()的所有调用,再根据调用顺序、入参特征给不同位置的调用返回差异化结果,以下是几种可直接落地的写法:
方案1:按调用顺序返回固定值(最常用)
如果两个add()调用的先后顺序固定,不需要额外判断入参,可以直接借助mock的side_effect参数传入返回值列表,mock会按调用顺序依次返回列表内的元素。
注意patch路径必须填调用add的模块下的引用,也就是
file1.add,如果填abc.add会因为模块提前导入引用导致patch不生效。
# 先安装pytest-mock:pip install pytest-mock def test_xyz(mocker): # 第一次调用add(i,j)返回100,第二次调用add(v,u)返回200 mock_add = mocker.patch("file1.add", side_effect=[100, 200]) # 执行被测函数 xyz() # 可选:校验调用行为是否符合预期 # 校验总共调用了2次add assert mock_add.call_count == 2 # 校验两次调用的入参分别对应i,j和v,u(替换成你代码里的实际值即可) mock_add.assert_any_call(i, j) mock_add.assert_any_call(v, u)
方案2:根据入参动态返回结果
如果需要根据入参匹配对应调用、返回不同结果,可以给side_effect传入自定义逻辑函数,在函数内判断入参返回对应值:
def test_xyz(mocker): def fake_add(a, b): # 匹配第一次调用的入参特征,比如i=2、j=3时返回100 if a == 2 and b == 3: return 100 # 匹配第二次调用的入参特征,比如v=4、u=5时返回200 if a == 4 and b == 5: return 200 # 兜底逻辑:不匹配的场景可以返回真实计算结果,或者抛出异常 return a + b mocker.patch("file1.add", side_effect=fake_add) # 执行被测函数+写业务断言即可 xyz()
方案3:用pytest原生monkeypatch实现(无需额外安装插件)
如果不想安装pytest-mock,用pytest自带的monkeypatch fixture也能实现,只需要自己维护一个调用计数器即可:
def test_xyz(monkeypatch): call_times = 0 def fake_add(a, b): nonlocal call_times call_times += 1 if call_times == 1: return 100 if call_times == 2: return 200 return a + b # 替换file1模块下的add引用 monkeypatch.setattr("file1.add", fake_add) # 执行被测函数+写业务断言 xyz() assert call_times == 2
常见踩坑点
- patch路径错误:一定要patch
file1.add,也就是被测试模块里导入的add引用,不要patch原定义模块abc.add - 不要重复打同一个方法的patch:后执行的patch会覆盖前面的,永远只会生效最后一个
- 如果调用次数和预期不符,可以在fake函数里加打印日志排查,确认被测函数的执行逻辑和预期一致
内容的提问来源于stack exchange,提问作者basp
相关产品推荐
相关产品推荐

