Python 模拟调用属性不';不要嘲笑这个函数
我试图用以下方式模拟函数:Python 模拟调用属性不';不要嘲笑这个函数,python,unit-testing,mocking,python-unittest,Python,Unit Testing,Mocking,Python Unittest,我试图用以下方式模拟函数: def foo(x): return 10 * x from unittest.mock import patch with patch.object(foo, "__call__", lambda x: 100 * x): print(foo(5)) print(foo.__call__(5)) 但是,输出如下所示: 50 500 而不是 500 500 也就是说,foo(5)不使用模拟的\uuu调用\uu属性。我假设像foo(5)
def foo(x):
return 10 * x
from unittest.mock import patch
with patch.object(foo, "__call__", lambda x: 100 * x):
print(foo(5))
print(foo.__call__(5))
但是,输出如下所示:
50
500
而不是
500
500
也就是说,foo(5)
不使用模拟的\uuu调用\uu
属性。我假设像foo(5)
这样的函数调用总是转换为foo.\uu调用\uuu(5)
。显然不是这样,但我不知道为什么。是否可以使用patch.object
模拟函数
我知道我可以用补丁(“path.to.foo”,lambda x:100*x)
来修补它,但我希望我可以在不需要知道路径的情况下修补对象。但也许我只需要做一些事情,比如:
patch(foo.__module__+'.'+foo.__name__, lambda x: 100*x)
但我不确定这是否是一种很好的修补方法。对我来说,这看起来像是自找麻烦,但我不确定那会是什么麻烦
那么,如何修补函数对象呢?foo(5)
转换为type(foo)。\uuuu调用\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
因此,需要修改类的\uuuuu call\uuuu
方法,而不是实例。为了不干扰同一类的其他实例,应该从唯一的类创建实例,然后可以自由地修补该类
我找不到改变函数对象的类的方法,所以我为函数创建了一个简单的包装器,它将函数转换为一个唯一类的实例,同时仍与原始函数的行为类似。然后,可以修补该类的\uuu调用\uu
方法:
from unittest import mock
def mockable_function(f):
class Function():
def __call__(self, *args, **kwargs):
return f(*args, **kwargs)
return Function()
@mockable_function
def foo(x):
return 10 * x
with mock.patch.object(type(foo), "__call__", lambda _, x: 100 * x):
print(foo(5))
print(foo.__call__(5))
这将产生:
500
500
也许不是很漂亮,但至少有一种编写函数的方法可以用mock.patch.object
修改
根据我的测试,使用mock.patch(“some.module.foo,…)
的问题是,如果一些模块从some.module import foo
导入foo
作为,那么foo
不会受到影响,而使用mock.patch.object(foo,…)
它被正确地修补了。我不知道这里发生了什么,但我肯定事情是这样的,然后猴子修补可能会成为一场噩梦。然后是你已经注意到的在哪里修补的问题。即使你做对了,当你重新组织你的代码时,事情也会破裂。我只能建议你不要打补丁。一定有更好的解决方法。事实上,foo(5)
被转换为type(foo)。\uuuu调用(foo,5)
。另外,与X-Y问题的联系也是一个很好的观点。所以,我实际上想要实现的是:我有一些具有副作用的功能(例如,读取文件、查询数据库)。在单元测试中,为了简单起见,我想用纯模拟函数替换其中的一些函数,然后可以用纯方法测试调用这些副作用函数的其他函数。这可能不是一个完美的设计,但考虑到当前的代码库,这似乎是最好的方法。