Python 在Django单元测试中使用mock修补芹菜任务

Python 在Django单元测试中使用mock修补芹菜任务,python,django,unit-testing,mocking,celery,Python,Django,Unit Testing,Mocking,Celery,我试图使用python模拟库来修补一个芹菜任务,该任务是在django应用程序中保存模型时运行的,以查看它是否被正确调用 基本上,任务是在myapp.tasks中定义的,并导入到my models.py文件的顶部,如下所示: from.tasks导入mytask …然后使用mytask.delay(foo,bar)在模型内部运行save()。到目前为止还不错-当我真的在运行Celeryd等时效果很好 我想构造一个模拟任务的单元测试,只是检查它是否被正确的参数调用,而不是实际运行芹菜任务 在测试文

我试图使用python模拟库来修补一个芹菜任务,该任务是在django应用程序中保存模型时运行的,以查看它是否被正确调用

基本上,任务是在myapp.tasks中定义的,并导入到my models.py文件的顶部,如下所示:

from.tasks导入mytask

…然后使用
mytask.delay(foo,bar)
在模型内部运行
save()
。到目前为止还不错-当我真的在运行Celeryd等时效果很好

我想构造一个模拟任务的单元测试,只是检查它是否被正确的参数调用,而不是实际运行芹菜任务

在测试文件中,我在标准测试用例中得到了如下内容:

from mock import patch # at the top of the file

# ...then later
def test_celery_task(self):
    with patch('myapp.models.mytask.delay') as mock_task:
        # ...create an instance of the model and save it etc
        self.assertTrue(mock_task.called)
…但它从未被调用/总是错误的。我尝试过各种不同的版本(改为修补
myapp.models.mytask
,并检查是否调用了
mock_task.delay
。我从模拟文档中收集到,导入路径至关重要,谷歌告诉我,它应该是在测试模块中看到的路径(如果我理解正确,应该是
myapp.models.mytask.delay
而不是
myapp.tasks.mytask.delay


我在这里哪里出错了?在修补芹菜任务时是否存在一些特定的困难?我是否可以修补
芹菜.task
(它被用作
mytask
)的装饰程序?

您遇到的问题与这是芹菜任务这一事实无关。您只是碰巧修补了错误的东西。;)

具体来说,您需要找出哪个视图或其他文件正在导入“mytask”,并在那里对其进行修补,因此相关行如下所示:

with patch('myapp.myview.mytask.delay') as mock_task:
这里有更多的味道:


装饰器将函数替换为
任务
对象(请参见)。如果您模拟任务本身,您将用
MagicMock
替换(有点神奇的)
任务
对象,它根本不会安排任务。相反,模拟
任务
对象的
run()
方法,如下所示:

@override_settings(CELERY_ALWAYS_EAGER=True)
@patch('monitor.tasks.monitor_user.run')
def test_monitor_all(self, monitor_user):
    """
    Test monitor.all task
    """

    user = ApiUserFactory()
    tasks.monitor_all.delay()
    monitor_user.assert_called_once_with(user.key)

你试过设置“芹菜总是渴望=真”而不是模仿它吗?干杯!我还没有尝试过(项目现在处于休眠状态),但很快就会尝试,并将其标记为已回答。我似乎记得我尝试过你建议的主题的一系列变化,但完全可能当时我的血糖低…:-)事实上,我正按照你的建议做这件事,如问题代码所示。。。无法让它工作。哦,好吧,问题是修补模型。这听起来有点不对,因为我怀疑您在模型中没有使用“delay”,而是在其他地方-可能是一个视图,因此我的修补程序代码(上面)略有不同。实际上,我正在调用模型上被重写的
save()
方法中的
mytask.delay()
。(我正在使用该任务将一些数据从模型发送到外部系统)。这会对补丁的工作方式产生影响吗?我回去从头开始尝试了一切:这次效果很好。不知道我以前做错了什么,但我很高兴。:-)你把这个答案逐字逐句地贴在两个问题上,有什么原因吗?@Micheled'Amico:我不同意,这个答案涉及到了一个具体问题,即如果你嘲笑任务本身,它就无法运行,这就解释了这个问题。模拟
delay()
方法,虽然可能在特定情况下工作,但实际上是错误的答案,因为您以后可能会将代码更改为使用
apply\u async()
或其他方法,突然您的测试将因错误原因中断。+1@DanielleMadeley。我最初修补了延迟,测试效果很好,直到我们需要将它们作为子任务进行链接,所有事情都在一个混乱的过程中南下!在较新的版本中,我们需要使用
cellery\u TASK\u ALWAYS\u EAGER
我认为这是一个更好的答案,因为它适用于链式任务以及使用
apply\u async
调用的任务(提供
倒计时
参数)。