测试函数上方使用@patch与函数内使用with patch的差异
@patch装饰器与with patch语句的核心区别
1. 作用范围不一样
- @patch装饰器:从测试函数开始执行前就完成patch,覆盖整个测试函数的生命周期,函数执行完自动撤销patch。
- with patch语句:只在
with包裹的代码块内生效,进入块时patch,退出块(哪怕抛异常)立刻撤销。
2. 作用域与mock覆盖逻辑有差异
- @patch装饰器:需要把mock对象作为参数传入测试函数,整个函数内都能调用这个mock。但如果函数内部又用
with patch处理同一个路径,会直接覆盖装饰器创建的mock——这就是你遇到装饰器不生效的原因:内部的with语句重新patch了my_path,把装饰器的设置(比如return_value=None)给覆盖了。 - with patch语句:mock通过
as绑定成局部变量,只在with块内有效,块外还是用原对象(或装饰器创建的mock,如果同时用了装饰器的话)。
3. 适用场景不同
- 要是整个测试函数都需要patch同一个对象,用@patch装饰器更简洁,不用嵌套代码块。
- 要是只有测试里的部分代码需要patch,或者需要在函数内多次切换同一个对象的mock状态,用with patch更灵活。
针对你问题的修复示例
你的代码里装饰器被内部with语句覆盖了,要让装饰器生效,删掉内部的with patch,直接用传入的mock参数就行:
@patch( "my_path", return_value=None, ) def test_function_to_test(mock_): # 直接使用装饰器创建的mock对象 instance = MyClass("a", "b") instance.function_to_test() # 可以断言mock的调用情况 mock_.assert_called_once()
如果确实需要临时patch,注意避免作用域冲突:
@patch("my_path", return_value=None) def test_function_to_test(mock_decorator): # 这里用的是装饰器的mock print(mock_decorator.return_value) # 输出None # 临时用新mock覆盖,仅在with块内生效 with patch("my_path", return_value="temp") as mock_with: print(mock_with.return_value) # 输出"temp" # 退出with块后,回到装饰器的mock print(mock_decorator.return_value) # 输出None
内容的提问来源于stack exchange,提问作者Roma V
相关产品推荐
相关产品推荐

