Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Unit Testing with two mock objects, how to verify call-order?

I'm writing a class that orchestrates two instruments (a remote controllable power supply unit and a bus controller used to control the Device-Under-Test) in order to perform all kinds of measurements on a Device-Under-Test (DUT).

Access to both instruments is implemented as Python classes and a reference to each is available to the new class. The DUT is somewhat delicate and has a very specific power-up sequence involving calls to the power supply and bus controller and has to happen in that specific order to avoid damaging the DUT.

Now I want to write a unit-test for this class. I am currently using nosetests and the mock-package for this. So my idea was to mock both instrument classes and verify the correct call order for those.

It seems to be very easy to verify the call order for each mocked class itself. Hence, I am able to find out if the power supply was ordered to correctly apply battery voltage first, then digital domain voltage and then analog domain voltage. I can also find out that the digital registers have been programmed to the correct values. However, I'm stuck determining if the call to write the digital registers happened between applying the digital domain voltage and analog domain voltage.

So my question is: If I have two mocked objects, how can I verify a specific order of calls between those objects? My first though was to check timestamps of the calls but those don't seem to exist.

like image 358
jan Avatar asked Apr 20 '15 13:04

jan


1 Answers

What you can do is put your mocks in a new Mock() object and check the mock's calls of the new mock. Maybe an example is simpler to understand:

>>> from unittest.mock import *
>>> m0, m1 = Mock(), Mock()
>>> m = Mock()
>>> m.m0, m.m1 = m0, m1
>>> m0()
<Mock name='mock.m0()' id='140660445334224'>
>>> m1()
<Mock name='mock.m1()' id='140660445334608'>
>>> m.mock_calls
[call.m0(), call.m1()]

Ok now we are in good position: we can just check the calls of m to verify the correct order:

>>> m.assert_has_calls([call.m0(), call.m1()])
>>> m.assert_has_calls([call.m1(), call.m0()])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/mock.py", line 863, in assert_has_calls
    'Actual: %r' % (calls, self.mock_calls)
AssertionError: Calls not found.
Expected: [call.m1(), call.m0()]
Actual: [call.m0(), call.m1()]

As we want the first pass and the inverse order fail.

When you use patch simply take the mocks returned by the patches and put them in a new Mock() as container. Do your check on the container that record the child calls order.

like image 79
Michele d'Amico Avatar answered Oct 02 '22 07:10

Michele d'Amico