Python 如何在multiprocessing.Pool中使用函数run中的mock
在我的代码中,我使用multiprocessing.Pool并发运行一些代码。简化的代码看起来有点像这样:Python 如何在multiprocessing.Pool中使用函数run中的mock,python,python-3.x,unit-testing,mocking,python-multiprocessing,Python,Python 3.x,Unit Testing,Mocking,Python Multiprocessing,在我的代码中,我使用multiprocessing.Pool并发运行一些代码。简化的代码看起来有点像这样: class Wrapper(): session: Session def __init__(self): self.session = requests.Session() # Session initialization def upload_documents
class Wrapper():
session: Session
def __init__(self):
self.session = requests.Session()
# Session initialization
def upload_documents(docs):
with Pool(4) as pool:
upload_file = partial(self.upload_document)
pool.starmap(upload_file, documents)
summary = create_summary(documents)
self.upload_document(summary)
def upload_document(doc):
self.post(doc)
def post(data):
self.session.post(self.url, data, other_params)
因此,通过HTTP发送文档基本上是并行的。现在我想测试这段代码,但却做不到。这是我的测试:
@patch.object(Session, 'post')
def test_study_upload(self, post_mock):
response_mock = Mock()
post_mock.return_value = response_mock
response_mock.ok = True
with Wrapper() as wrapper:
wrapper.upload_documents(documents)
mc = post_mock.mock_calls
在调试中,我可以检查模拟调用。有一个看起来有效,就是上传摘要的那个,还有一堆调用,比如call.json()
,call.\uu len\uu()
,call.\uu str\uu()
等等
没有上传文档的电话。当我在upload\u document
方法中设置断点时,我可以看到它对每个文档调用了一次,它按预期工作。但是,我无法测试它,因为我无法通过模拟来验证此行为。我认为这是因为有许多进程调用同一个mock,但仍然-我如何解决这个问题
我使用Python3.6,这里我将采用的方法是使测试尽可能细化,并模拟其他调用。在这种情况下,您希望模拟
池
对象,并验证它调用的是您期望的内容,而不是在测试期间实际依赖它来加速子进程。以下是我的想法:
@patch('yourmodule.Pool')
def test_study_upload(self, mock_pool_init):
mock_pool_instance = mock_pool_init.return_value.__enter__.return_value
with Wrapper() as wrapper:
wrapper.upload_documents(documents)
# To get the upload file arg here, you'll need to either mock the partial call here,
# or actually call it and get the return value
mock_pool_instance.starmap.assert_called_once_with_args(upload_file, documents)
然后,您需要使用现有逻辑并单独测试上载文档功能:
@patch.object(Session, 'post')
def test_upload_file(self, post_mock):
response_mock = Mock()
post_mock.return_value = response_mock
response_mock.ok = True
with Wrapper() as wrapper:
wrapper.upload_document(document)
mc = post_mock.mock_calls
这使您可以覆盖创建和控制池的函数,以及池实例调用的函数。注意:我没有测试这个,但我会留下一些给你来填补空白,因为它看起来像是你原始问题中实际模块的缩写版本
编辑:
试试这个:
def test_study_upload(self):
def call_direct(func_var, documents):
return func_var(documents)
with patch('yourmodule.Pool.starmap', new=call_direct)
with Wrapper() as wrapper:
wrapper.upload_documents(documents)
这是对starmap调用的修补,以便它直接调用您传入的函数。它完全绕过游泳池;底线是,您不能真正深入到由多处理创建的子流程中。谢谢,看起来这是唯一的方法。然而,失去集成测试让我感到悲哀。我认为它更像是:如果您正在测试您的池已经处理的函数,并且您正在测试处理向池中添加任务的函数,那么您就完全被覆盖了!也许有另一种方法,只需修补星图。我将用建议编辑我的问题@阿莫菲斯