Unit test python udev interaction
Question: I've inherited some python code that writes a new '/etc/udev/rules.d' mapping
file and then makes a subprocess call to udev to have it refresh its devices
list:

    
    
    call(['/sbin/udevadm', 'trigger', '--action=change'])
    

The trigger call is necessary as we need the mapping to update without wanting
to unplug and plug back in the device being mapped. My problem is the 'call'
line was removed at one point, causing non-obvious side-effects in other parts
of the program and so was not caught.

My usual way of fixing something like this is to throw a unit-test on this
method (which writes the mapping file and calls trigger) to enforce the
expected behaviour, but this behaviour seems outside of the realm of unit-
testing. It's a system call, not to mention udevadm trigger requires sudo
access. I can't figure out how/what to mock out in this instance.

I considered using the pyudev library as I saw that it can mock certain
behaviour of udev, but it doesn't look like it can mock the trigger behaviour
(or even access it for that matter).

Short of throwing a big "#DO NOT DELETE THIS LINE EVER!" above the "call"
line, is there anything I can do here to prevent this from being removed in
the future? "DO NOT DELETE" lines are easily ignored say a year from now when
no one has a clue why it's there.


Answer: Here's what I decided to do in this instance, if anyone disagrees with my
answer please chime in!

It's a two parter.

First I wrapped the call I was concerned about and switched the straight
'call' to this in my code.

    
    
    class UdevWrapper:
        def udevadm_trigger(self):
            call(['/sbin/udevadm', 'trigger', '--action=change'])
    

(The class contains more than this, just simplified here for clarity)

Next I mocked out the wrapper method and tested to ensure that it was called

    
    
    @patch.object(utils.UdevWrapper,'udevadm_trigger')
    def test_trigger_called(self,mock_udevadm_trigger):
        mock_udevadm_trigger.return_value = True
    
        # name changed for clarity
        ClassWhereTriggerCalled.func()
        assert mock_udevadm_trigger.called
    

Doing it this way was inspired by reading about [Behaviour Driven
Development](http://dannorth.net/introducing-bdd/). The whole idea of BDD is
brand new to me so I'm not sure stylistically/functionally how BDD proponents
will feel about my solution but it does what I wanted - something obviously
breaks (my test) if this line of code is removed in the future.

I plan on switching it to use _monkeypatch_ in the future so that I can create
a stub function that can check state (the order in which trigger is called is
also important). However the principle remains the same:

  1. Wrap in a method that can be mocked
  2. Write test to ensure correct functional behaviour
  3. Mock wrapped method

