Reference a nested function in unittest assert_called_with()

993 Views Asked by At

How can I reference nested functions in MagicMock.<method>.assert_called_with()?

I want to mock an object (called here EventObject) that can distribute events to installed event handlers.

The signature for handler installation looks like this:

class EventObject:
    def install_handler(handler_func):
        pass

A function that installs as event handler a nested function:

def setup_handler(event_obj):
    def handle_event():
        pass

    event_obj.install_handler(handle_event)

Now how to test this? I tried:

def test_listen():
    event_obj = MagicMock(spec=EventObject)
    setup_handler(event_obj)
    event_obj.install_handler.assert_called_with(setup_handler.handle_event)

But this gives AttributeError: 'function' object has no attribute 'handle_event'.

Any ideas?

1

There are 1 best solutions below

0
On BEST ANSWER

You can't access handle_event - it's not an attribute of setup_handler, it's just a local variable and therefore inaccessible outside that scope. All you can say outside setup_handler is that the install_handler attribute got called with something, e.g. using ANY:

def test_listen():
    event_obj = MagicMock(spec=EventObject)
    setup_handler(event_obj)
    event_obj.install_handler.assert_called_with(ANY)

(See my answer to Specifying "any instance of class Foo" for mock assert_called_once_with()? for more specific assertions - you could do e.g. AnyInstanceOf(Callable) instead.)

However, given that the function's being passed to install_handler, which is now mocked out, you can then test that this function does the right thing by accessing it on the mock_calls and interacting with it:

def test_listen():
    event_obj = MagicMock(spec=EventObject)
    setup_handler(event_obj)
    handler = event_obj.install_handler.mock_calls[0].args[0]
    # exercise handler