The mocking library I use is ... mock.
I came across this "mock nested functions" problem when I tried to write test case for a function(legacy code).
This function used a very complex nested function with heavy dependencies on other modules.
I wonder if it's possible to mock nested functions with mock
.
for example you need to mock nested function calls (chained functions) from Google DRIVE API
result = get_drive_service().files().insert(body='body', convert=True).execute()
so you need to patch through functions: service_mock(), files(), insert(), till last execute() response:
from mock import patch
with patch('path.to.import.get_drive_service') as service_mock:
service_mock.return_value.files.return_value.insert.\
return_value.execute.return_value = {'key': 'value', 'status': 200}
Main scheme:
first.return_value.second.return_value.third.return_value.last.return_value = rsp
One option is to change your function so that it optionally accepts the function to call e.g. if you have:
def fn_to_test():
def inner_fn():
return 1
return inner_fn() + 3
Change it to:
def fn_to_test( inner_fn = null )
def inner_fn_orig():
return 1
if inner_fn==null:
inner_fn = inner_fn_orig
return fn() + 3
Then "real" uses will get the right inner function, and in your tests you can provide your own.
fn_to_test() # calls the real inner function
def my_inner_fn():
return 3
fn_to_test( inner_fn=my_inner_fn ) # calls the new version
You could also do this:
def fn_to_test():
def inner_fn_orign():
return 1
inner_fn = inner_fn_orig
try:
inner_fn = fn_to_test.inner_fn
excecpt AttributeError:
pass
return inner_fn() + 3
This way you just define the override:
fn_to_test() # calls the real inner function
def my_inner_fn():
return 3
fn_to_test.inner_fn = my_inner_fn
fn_to_test() # calls the new version
Are you trying to replace a nested function with a mock object? If so, that's fairly straightforward, no matter how complicated the function is. You can use a MagicMock to replace pretty much any python object.
If you need to simulate a function that returns something, you can just set the MagicMock
's return_value
parameter. It would look something like this:
>>> super_nested_mock = mock.MagicMock()
>>> super_nested_mock.return_value = 42
>>> super_nested_mock()
42
However, if you're trying to test another piece of code that calls your super_nested
function somewhere inside, and want to mock it out, you'll need to use a patch. In the mock library, it will look something like this:
with patch('super_nested') as super_nested_mock:
super_nested_mock.return_value = "A good value to test with"
assert my_function_that_calls_super_nested(5) == 20
Here, anything in the with
block that would normally call super_nested
instead will call the super_nested_mock
and just return the value that you set to it.
There is some subtlety to what exactly you need to put in the patch call. Mainly, you want to patch the object as the module you're testing would see it. See "where to patch" for more instruction.
The only way I've seen this done is to dynamically create a copy of your outer function, modifying the function's code object constants with the code for your mocked function:
Does an equivalent of override exist for nested functions?