kaste / mockito-python

Mockito is a spying framework
MIT License
123 stars 12 forks source link

How to verify stubbed methods (from different mocks) are called in order? #68

Open ghost opened 1 year ago

ghost commented 1 year ago

Hello,

I didn’t find this information in the documentation, so how would I achieve that?

E.g. Makes sure that this passes:

verify(self._subscriber1, times=1).run('data')
verify(self._subscriber2, times=1).run('data')
verify(self._subscriber3, times=1).run('data')

but this fails

verify(self._subscriber3, times=1).run('data')
verify(self._subscriber2, times=1).run('data')
verify(self._subscriber1, times=1).run('data')

Thank you

kaste commented 1 year ago

That's not implemented. inorder.verify is for one mock or mocked object. There is no global storage for invocations, so we don't have this information at hand.

kaste commented 1 year ago

I used code like this in the past:

def test():
    message = []
    def record_message(message):
        messages.append(message)

    when(subscriber1).run(msg).thenAnswer(record_message)

If that works:

    patch(subscriber1, recordMessage)  # instead of `when...thenAnswer` may read better
ghost commented 1 year ago

From thousands of tests, that is really the first time I would like to test that, because in my observer implementation, order of execution is essential.

I guess I could record calls myself in an ordered list as you suggest and verify afterwards.

Thanks @kaste.

stevenengland commented 1 year ago

Hi @gui-don , can you please provide a code snippet demonstrating the complete flow? I think this might also be interesting as a recipe in the docs.

ghost commented 1 year ago

Hi @stevenengland,

I solved this in a non-generic way. I used the "stop_propagation" pattern to test order in my case.

Given these mocks:

[…]
self._subscriber_x = mock(EventSubscriber)
when(self._subscriber_x).get_order().thenReturn(2)
when(self._subscriber_x).must_stop_propagation().thenReturn(False)

[…]
self._subscriber_stop = mock(EventSubscriber)
when(self._subscriber_stop).get_order().thenReturn(1)
when(self._subscriber_stop).must_stop_propagation().thenReturn(True)

And the subject I’m testing, where order is important:

self._subject = MyEventDispatcher(subscribers=[…])

Then just:


self._subject.register(self._subscriber_stop)

verify(self._subscriber_stop, times=1).run('data')
verify(self._subscriber2, times=0).run(...)
[…]

verifyNoMoreInteractions()

If order of my subject was not working, then other subscribers besides the subscriber_stop would be called. I do not think it’s worth documenting. It does work here, thanks to must_stop_propagation(), a wanted feature. I don’t think people are gonna create public methods just to test their code :(