jwd
jwd

Reputation: 11114

pytest: how do I get the (mock) instances returned from a mocked class?

I must be tired, because surely there is an easy way to do this. But I've read over the pytest docs and can't figure out this simple use case.

I have a little package I want to test:

class MyClass:
    def __init__(self):
        pass
    def my_method(self, arg):
        pass

def the_main_method():
    m = MyClass()
    m.my_method(123)

I would like to ensure that (1) an instance of MyClass is created, and that (2) my_method is called, with the proper arguments.

So here's my test:

from unittest.mock import patch

@patch('mypkg.MyClass', autospec=True)
def test_all(mocked_class):

    # Call the real production code, with the class mocked.
    import mypkg
    mypkg.the_main_method()

    # Ensure an instance of MyClass was created.
    mocked_class.assert_called_once_with()

    # But how do I ensure that "my_method" was called?
    # I want something like mocked_class.get_returned_values() ...

I understand that each time the production code calls MyClass() the unittest framework whips up a new mocked instance.

But how do I get my hands on those instances?

I want to write something like:

the_instance.assert_called_once_with(123)

But where do I get the_instance from?

Upvotes: 2

Views: 2714

Answers (1)

jwd
jwd

Reputation: 11114

Well, to my surprise, there is only one mock instance created, no matter how many times you call the constructor (:

What I can write is:

mocked_class.return_value.my_method.assert_called_once_with(123)

The return_value does not represent one return value, though — it accumulates information for all created instances.

It's a rather abstruse approach, in my mind. I assume it was copied from some crazy Java mocking library (:

If you want to capture individual returned objects, you can use .side_effect to return whatever you want, and record it in your own list, etc.

Upvotes: 1

Related Questions