我编写了一个继承 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 中的对象存在一些问题。这提出了两个问题:
我真的很感激任何帮助...
编辑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)
答案 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。只需编写自己的模拟类。