Is there a simple way to trace function calls in a complex call without mocking everything separately?

Viewed 40

Assume that I don't care about occurring exceptions at all. I have a complex function that calls multiple functions along the way.. I want to test that with certain input parameters, certain functions will be called.

So basically, I am looking for something like:

@patch(
    "service.module.class.some_nested_function_1",
    new_callable=AsyncMock,
)
@patch(
    "service.module.class.some_nested_function_2",
    new_callable=AsyncMock,
)
@pytest.mark.asyncio
async def test_complex_function(function2_mock, function1_mock):
    some_param = "abc"
    another_param = "xyz"
    try:
        call_complex_function("with_some_configuration")
    except:
        abort_crashing_function_and_continue_execution_in_complex_function()
    assert function2_mock.assert_called_once_with(some_param)
    assert function1_mock.assert_called_once_with(another_param)

EDIT: An alternative idea would be to have something like:

...
async def test_complex_function(function2_mock, function1_mock):
    ...
    mock_every_function_call_except_complex_function_to_return_zero()
    call_complex_function("with_some_configuration")
    assert function2_mock.assert_called_once_with(some_param)
    assert function1_mock.assert_called_once_with(another_param)
    ...
...
1 Answers

Function Call Counting Wrapper

Wrap your nested functions with this so that mocks aren't necessary and you can still see if certain functions were called or not called.

def count_calls_wrapper(fn):
    call_count = 0

    def _result(*args):
        nonlocal call_count
        call_count +=1
        return fn(*args)

    def _get_call_count():
        return call_count

    _result.get_call_count = _get_call_count

    return _result


def f1():
    return 10

f1 = count_calls_wrapper(f1)

assert(f1.get_call_count() == 0)

f1()

assert(f1.get_call_count() == 1)
Related