我编写了一个继承 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,我会得到完全相同的错误(例如,将上面代码中的第 13 行替换为 *self._some_class = lambda x: x/2 *)。所以我的猜测是在产生新进程时复制 MyProcess 中的对象存在一些问题。这就提出了两个问题:
我真的很感激任何帮助......
编辑 1(有关错误消息的更多信息):
如果我取消注释 main 函数中的行,我会收到一堆错误,我认为以下应该是相关的错误:
pickle.PicklingError: Can't pickle : 它与 mock.Mock 不是同一个对象
编辑2(找到一些相关信息):
我在谷歌代码上发现了以下issue,这似乎与我的问题有关。实际上,将主函数中的模拟更改为以下内容会使代码可执行:
proc._some_class = mock.MagicMock()
proc._some_class.__class__ = mock.MagicMock
但是,我对测试感兴趣的是以下调用:proc._some_class.some_method.call,尽管该方法显然已被调用,但它始终为 False。我想这与我上面提到的解决方法有关。
编辑 3(基于 jb 的建议的解决方法。):
可以通过直接调用 run 方法来解决这个问题。以下代码包含 main 函数并展示了如何使用模拟测试该函数:
if __name__ == '__main__':
proc = MyProcess()
proc._some_class = mock.MagicMock()
proc.run()
print(proc._some_class.sum.called)
最佳答案
虽然这不能直接解决您的问题,但请考虑以下方法。从 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 多处理接口(interface)依赖于 pickling ,而模拟库和酸洗不要去 well together 。只需编写自己的模拟类。
关于继承多处理 : mocking one of the class objects 的 Python 类,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26094560/