我有一个返回布尔值的函数列表。 都是这样称呼的:
for f in functions:
if f():
pass
我正在编写测试,我想模拟这些函数的结果
@pytest.fixture
def is_first_func_mock(mocker):
mock = mocker.patch.object(SomeClass, 'first_func')
return mock
然后在测试的某个地方我通过了这个固定装置并编写
is_first_func_mock.return_value = True
或类似的东西
但是由于我没有直接在代码中调用该函数,并且由于我在上面指出了这一点,所以模拟不起作用。
我在Stackoverflow找到了解决方案: 我可以这样调用函数:
if getattr(funcs_module, func.__name__)():
pass
但我不喜欢它,也不想改变循环
更新:
def some_name(fucntions: list[callable]):
def inner(func):
@wraps(func)
async def wrapper(*args, **kwargs):
#some code
for f in functions:
if f():
return await func(*args, **kwargs)
raise SomePermission
return wrapper
return inner
我还没有找到解决方案,但这里有一个解决方法:
from functools import wraps
def has_any_permissions(get_functions):
def inner(func):
@wraps(func)
async def wrapper(*args, **kwargs):
# some code
funcs = get_functions()
if any(f() for f in funcs):
return await func(*args, **kwargs)
raise SomePermission()
return wrapper
return inner
def is_admin():
return False
def is_users_moderator():
return False
def admin_and_users_moderator():
return [is_admin, is_users_moderator]
@has_any_permissions(admin_and_users_moderator)
def about_user():
return 'user' # just for demonstration purposes
我不得不引入一些间接方法,其中装饰器在装饰时不会绑定实际的函数列表,而是提供一个函数,当在
wrapper()
内部调用时,每次可以调用目标时都会获取函数。
相应的单元测试可能如下所示:
import unittest
from unittest.mock import patch
from mockable_functions import about_user
class Test(unittest.TestCase):
def test_plain_function_raises(self):
self.assertRaises(SomePermission, about_user)
@patch('mockable_functions.is_admin')
def test_func(self, is_admin_mock):
is_admin_mock.return_value = True
self.assertEqual(about_user(), 'user', 'about_user returns user')
此单元测试表明,正常调用时
about_user()
会引发错误,但是当修补 is_admin
函数时,则会调用真实函数(并返回虚拟值)