user893238
user893238

Reputation:

Asserting an object passed into a mocked method in the python mock

Say I have a class called Client that creates an object of the Request class and passes it to a method of a Connection object:

class Client(object):
    def __init__(self, connection):
        self._conn = connection

    def sendText(plaintext):
        self._conn.send(Request(0, plaintext))

And I want to assert the object passed into the Connection.send method to check its properties. I start with creating a mocked Connection class:

conn = Mock()

client = Client(conn)
client.sendText('some message')

And then I want something like:

conn.send.assert_called_with(
    (Request,
    {'type': 0, 'text': 'some message'})
)

Where 'type' and 'text' are properties of Request. Is there a way to do this in python's mock? All I found in the documentation were simple data examples. I could have done it with mock.patch decorator by replacing the original 'send' method with a method which asserts the object's fields:

def patchedSend(self, req):
    assert req.Type == 0

with mock.patch.object(Connection, 'send', TestClient.patchedSend):
    ...

but in this case I would have to define a separete mocked function for every method check and I couldn't check (without additional coding) if the function has been called at all.

Upvotes: 7

Views: 10121

Answers (2)

Gabriel Jordão
Gabriel Jordão

Reputation: 778

Well, I think that the easiest and better way of doing it, in this specific case, is to make a function to create requests and then mock it.

For instance, it'd be something like it:

class Client(object):
    def __init__(self, connection):
        self._conn = connection

    def _create_request(self, plain_text):
        return Request(0, plain_text)

    def send_text(self, plaintext):
        self._conn.send(self._create_request(plain_text))

And then, in the test, you could mock _create_request to return some specific value and then assert that send_text was called with it.

You could also get the parameters by call_args, as suggested, but I think it looks better this way.

Upvotes: 0

user2357112
user2357112

Reputation: 280993

You can get the last arguments to the mock with

request, = conn.send.call_args

and then assert properties about that. If you want facilities to express more sophisticated assertions about things, you can install PyHamcrest.

Note: Don't use assert in unit tests. Use assertion methods like assertEqual or assertTrue. Assertion methods can't be accidentally turned off, and they can give more useful messages than assert statements.

Upvotes: 10

Related Questions