I have a list of functions that return Boolean values. It's all called like this:
for f in functions:
if f():
pass
I am writing tests and I want to mock the result of those functions
@pytest.fixture
def is_first_func_mock(mocker):
mock = mocker.patch.object(SomeClass, 'first_func')
return mock
and then somewhere in the test I pass this fixture and write
is_first_func_mock.return_value = True
or something like that
But since I'm not calling the function directly in the code, and since I indicated it above, the mock does not work.
I found a solution in Stackoverflow: I can call functions like that:
if getattr(funcs_module, func.__name__)():
pass
But I don't like it and I don't want to change the loop
Update:
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
I haven't been able to find a solution, but here is a workaround:
I have had to introduce some indirection where the decorator does not bind the actual list of functions at decoration time, but instead supplies a function which, when called inside
wrapper()
gets the functions each time the target could be called.The corresponding unit test might look like this:
This unit test shows that
about_user()
raises an error when called normally, but when theis_admin
function is patched, then the real function gets called (and returns a dummy value)