Python class inheriting multiprocessing: mocking one of the class objects
Question: I have written a class that inherits the _multiprocessing.Process()_ class. In
the initialization I set some parameters, one of them is another class that
writes to some file on my hard drive. For the purpose of unit testing I would
like to mock this class instance in order to avoid actually writing to some
file. Here is some minimal example:

    
    
    import mock
    import time
    import multiprocessing as mp
    import numpy as np
    
    class MyProcess(mp.Process):
    
        def __init__(self):
            super(MyProcess, self).__init__()
    
            # the original code would create some instance of a file manipulation
            # class here:
            self._some_class = np.zeros(100)
    
        def run(self):
    
            # the following line would actually write to some file in the original
            # code:
            self._some_class.sum()
    
            for ii in range(10):
                print(str(ii))
                time.sleep(.01)
    
    if __name__ == '__main__':
    
        proc = MyProcess()
    #     proc._some_class = mock.Mock()
    
        proc.start()
        proc.join()
    

The code above should run as is. However, if I try to mock the class
__some_class_ in the class _MyProcess_ (= uncommenting the line in the main
function) I get errors. Interestingly, I get the exact same errors if I try to
initialize _self._some_class_ with a function (e.g. replace line 13 in the
code above with *self._some_class = lambda x: x/2 *). So my guess is that
there is some problem with copying the objects in _MyProcess_ when a new
process is spawned. That raises two questions:

  * Could somebody shed some light why it is not possible to initialize a class object with a function?
  * How could I mock one of the class objects of _MyProcess_?

I would really appreciate any help...

EDIT 1 (more information on the error messages):

If I uncomment the line in the main function I get a bunch of errors, where I
think the following should be the relevant one:

pickle.PicklingError: Can't pickle : it's not the same object as mock.Mock

EDIT 2 (found some relevant information):

I found the following
[issue](https://code.google.com/p/mock/issues/detail?id=139) on google code,
which seems to be related to my problem. Indeed, changing the mock in the main
function to the following makes the code executable:

    
    
    proc._some_class = mock.MagicMock()
    proc._some_class.__class__ = mock.MagicMock
    

However, what I would be interested in for testing is the following call:
_proc._some_class.some_method.called_ , which is always _False_ despite the
fact that the method has obviously been called. I guess that has something to
do with the workaround that I mentioned above.

EDIT 3 (workaround based on the suggestion of jb.):

One can work around the issue by calling the _run_ method directly. The
following code contains the main function and shows how to test the function
using mocks:

    
    
    if __name__ == '__main__':
    
        proc = MyProcess()
        proc._some_class = mock.MagicMock()
        proc.run()
    
        print(proc._some_class.sum.called)
    


Answer: While this does not address your question directly, please consider following
approach. Inheriting from Process object might be make implementation easier,
but (as you noted) can be very hard when doing unit-testing.

It would be much easier if you pass `run` function as a parameter to `Process`
instance in that way you can test `run` function separately from the
multiprocessing enviorment. If you need to test `run` behaviour in another
process just create a callable object, and mock proper things inside.

Something along the lines:

    
    
    from multiprocessing import Process
    
    def f(name):
        print 'hello', name
    
    if __name__ == '__main__':
        p = Process(target=f, args=('bob',))
        p.start()
        p.join()
    

If you want to stick to your design you'd shouldn't use MagicMock, python
multiprocessing interface relies on
[pickling](https://docs.python.org/2.7/library/pickle.html), and mock library
and pickling don't go [well
together](https://code.google.com/p/mock/issues/detail?id=139). Just write
your own mocking class.

