使用patch模拟Python中的Celery任务调用
在使用模拟(mock)来修补一个Celery任务调用时,我得到的结果是<Mock name='mock().get()' ...>
,而不是我期望的通过mock_task.get.return_value = "value"
定义的return_value
。不过,在我的单元测试中,这个模拟的任务运行得很好。
这是我修补Celery任务的单元测试:
def test_foo(self):
mock_task = Mock()
mock_task.get = Mock(return_value={'success': True})
print mock_task.get() # outputs {'success': True}
with patch('app.tasks.my_task.delay', new=mock_task) as mocked_task:
foo() # this calls the mocked task with an argument, 'input from foo'
mock_tasked.assert_called_with('input from foo') # works
这是正在测试的函数:
def foo():
print tasks.my_task.delay # shows a Mock object, as expected
# now let's call get() on the mocked task:
task_result = tasks.my_task.delay('input from foo').get()
print task_result # => <Mock name='mock().get()' id='122741648'>
# unexpectedly, this does not return {'success': True}
if task_result['success']:
...
最后一行抛出了一个错误:TypeError: 'Mock' object has no attribute '__getitem__'
为什么我可以在单元测试中调用mock_task.get(),但是在foo
中调用它却返回了一个<Mock ...>
而不是我期望的返回值呢?
1 个回答
8
很遗憾,我对Celery几乎一无所知,但看起来问题出在模拟(mock)上。
你有:
tasks.my_task.delay('input from foo').get()
在执行patch('app.tasks.my_task.delay', new=mock_task)
之后,它变成了:
mock_task('input from foo').get()
这和下面的内容是不一样的:
mock_task.get()
你应该把模拟的创建改成:
mock_task().get = Mock(return_value={'success': True})
当你访问已有的模拟属性或调用它时,会默认创建一个新的模拟实例。所以我们可以稍微简化一下:
mock_task().get.return_value = {'success': True}