继承多处理的Python类:模拟其中一个类对象

时间:2014-09-29 07:25:52

标签: python unit-testing inheritance multiprocessing

我编写了一个继承 multiprocessing.Process()类的类。在初始化中我设置了一些参数,其中一个是写入我硬盘上某个文件的另一个类。出于单元测试的目的,我想模拟这个类实例,以避免实际写入某个文件。这是一个最小的例子:

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()

上面的代码应该按原样运行。但是,如果我尝试在类 MyProcess 中模拟类 _some_class (=取消注释main函数中的行),我会收到错误。有趣的是,如果我尝试使用函数初始化 self._some_class (例如,使用* self._some_class = lambda x:x / 2 *替换上面代码中的第13行),我会得到完全相同的错误。所以我的猜测是,在生成新进程时,复制 MyProcess 中的对象存在一些问题。这提出了两个问题:

  • 有人可以说明为什么无法使用函数初始化类对象吗?
  • 我如何模拟 MyProcess 的一个类对象?

我真的很感激任何帮助...

编辑1(有关错误消息的更多信息):

如果我取消注释main函数中的行,我会收到一堆错误,我认为以下内容应该是相关的:

pickle.PicklingError:不能发痒:它与mock.Mock不是同一个对象

编辑2(找到一些相关信息):

我在Google代码上发现了以下issue,这似乎与我的问题有关。实际上,将main函数中的mock更改为以下代码会使代码可执行:

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

但是,我对测试感兴趣的是以下调用: proc._some_class.some_method.called ,它总是 False ,尽管该方法的事实显然被称为。我想这与我上面提到的解决方法有关。

编辑3(根据jb的建议解决方法):

可以通过直接调用 run 方法来解决此问题。以下代码包含main函数,并显示如何使用mocks测试函数:

if __name__ == '__main__':

    proc = MyProcess()
    proc._some_class = mock.MagicMock()
    proc.run()

    print(proc._some_class.sum.called)

1 个答案:

答案 0 :(得分:2)

虽然这不能直接解决您的问题,但请考虑以下方法。继承Process对象可能会使实现更容易,但(如您所述)在进行单元测试时可能非常困难。

如果将run函数作为参数传递给Process实例会更容易,因为您可以在多处理环境中单独测试run函数。如果您需要在另一个进程中测试run行为,只需创建一个可调用对象,并在其中模拟适当的内容。

有些事情:

from multiprocessing import Process

def f(name):
    print 'hello', name

if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()

如果你想坚持你的设计,你不应该使用MagicMock,python多处理接口依赖于pickling,模拟库和酸洗不会使用well together。只需编写自己的模拟类。