Python 在pytest中模拟模块级函数
我有一个功能,有一个装饰。decorator接受参数,并且参数的值是从另一个函数调用派生的 示例.pyPython 在pytest中模拟模块级函数,python,module,mocking,pytest,decorator,Python,Module,Mocking,Pytest,Decorator,我有一个功能,有一个装饰。decorator接受参数,并且参数的值是从另一个函数调用派生的 示例.py from cachetools import cached from cachetools import TTLCache from other import get_value @cached(cache=TTLCache(maxsize=1, ttl=get_value('cache_ttl'))) def my_func(): return 'result' 其他的 de
from cachetools import cached
from cachetools import TTLCache
from other import get_value
@cached(cache=TTLCache(maxsize=1, ttl=get_value('cache_ttl')))
def my_func():
return 'result'
其他的
def get_value(key):
data = {
'cache_ttl': 10,
}
# Let's assume here we launch a shuttle to the space too.
return data[key]
我想模拟调用get\u value()
。我在测试中使用了以下内容:
示例_test.py
import mock
import pytest
from example import my_func
@pytest.fixture
def mock_get_value():
with mock.patch(
"example.get_value",
autospec=True,
) as _mock:
yield _mock
def test_my_func(mock_get_value):
assert my_func() == 'result'
这里我正在注入
mock\u get\u value
来测试我的函数。但是,由于在第一次导入时调用了我的decorator,get\u value()
会立即被调用。是否有办法在使用pytest立即导入模块之前模拟对get_value()
的调用?使用测试函数中的将从示例导入my_func
移动到中。在它真正来自的地方进行修补,other.get\u value
。这可能就是一切
Python将模块缓存在sys.modules
中,因此模块级代码(如函数定义)仅在从任何地方首次导入时运行。如果这不是第一次,您可以使用importlib.reload()
或删除sys.modules
中的相应键并再次导入来强制重新导入
请注意,重新导入模块可能会产生副作用,并且您可能还希望在运行测试后再次重新导入模块,以避免干扰其他测试。如果另一个模块正在使用重新导入的模块中定义的对象,这些对象不仅会消失,而且可能不会按预期的方式更新。例如,重新导入模块可能会创建第二个本应为单例的实例
一种更可靠的方法是将原始导入的模块对象保存到其他地方,从sys.modules
中删除,在测试期间使用补丁版本重新导入,然后在测试后将原始导入放回sys.modules
。您可以在sys.modules
上的patch.dict()上下文中导入
import mock
import sys
import pytest
@pytest.fixture
def mock_get_value():
with mock.patch(
"other.get_value",
autospec=True,
) as _mock, mock.patch.dict("sys.modules"):
sys.modules.pop("example", None)
yield _mock
def test_my_func(mock_get_value):
from example import my_func
assert my_func() == 'result'
另一种可能是在测试中自己在原始函数上调用decorator。如果装饰程序使用了functools.wrapps()
/functools.update\u wrapper()
,则原始函数应作为\uuuuuuuu wrapped\uuu
属性可用。这可能不可用,具体取决于装饰器的实现方式