用补丁模拟Python中的Celery任务调用

Mocking a Celery task call in Python with patch

使用模拟的返回值修补Celery任务调用将返回,而不是由mock_task.get.return_value ="value"定义的预期return_value。 但是,模拟的任务在我的单元测试中可以正常运行。

这是我修补Celery任务的单元测试:

1
2
3
4
5
6
7
8
9
10
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

这是正在测试的功能:

1
2
3
4
5
6
7
8
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调用它却返回而不是预期的返回值?


不幸的是,我对Celery几乎一无所知,但是看起来问题出在嘲弄。

你有:

1
tasks.my_task.delay('input from foo').get()

patch('app.tasks.my_task.delay', new=mock_task)之后,它变为:

1
mock_task('input from foo').get()

这与以下内容不同:

1
mock_task.get()

您应该将模拟创建更改为:

1
mock_task().get = Mock(return_value={'success': True})

当您访问现有的Mock属性或调用它时,默认情况下会创建新的Mock实例。 所以我们可以简化一下:

1
mock_task().get.return_value = {'success': True}