我有一个任务foobar
:
@app.task(bind=True)
def foobar(self, owner, a, b):
if already_working(owner): # check if a foobar task is already running for owner.
register_myself(self.request.id, owner) # add myself in the DB.
return a + b
如何模拟self.request.id
属性?我已修补所有内容并直接调用该任务而不是使用.delay/.apply_async
,但self.request.id
的值似乎是None
(因为我正在与DB进行真正的交互,它正在制作测试失败等...)。
作为参考,我使用Django作为框架,但我认为无论您使用的环境如何,这个问题都是一样的。
答案 0 :(得分:2)
免责声明:嗯,我不认为它是在某处记录的,而且这个答案可能与实现有关。
Celery将他的任务包装到celery.Task
实例中,我不知道它是否通过用户任务函数或其他任何方式交换celery.Task.run
方法。
但是,当你直接调用一个任务时,你会调用__call__
并且它会推送一个包含任务ID等的上下文......
所以我的想法是绕过__call__
和芹菜的常规工作,首先:
foobar.push_request(id=1)
。foobar.run(*args, **kwargs)
。示例:
@app.task(bind=True)
def foobar(self, name):
print(name)
return foobar.utils.polling(self.request.id)
@patch('foobar.utils.polling')
def test_foobar(mock_polling):
foobar.push_request(id=1)
mock_polling.return_value = "done"
assert foobar.run("test") == "done"
mock_polling.assert_called_once_with(1)
答案 1 :(得分:1)
您可以使用来同步调用任务
task = foobar.s(<args>).apply()
这将分配一个唯一的任务ID,因此该值将不会为None,并且您的代码将运行。然后,您可以在测试中检查结果。
答案 2 :(得分:0)
可能有一种方法可以使用 patch
执行此操作,但我无法找到分配属性的方法。最直接的方法就是模拟自己。
tasks.py:
@app.task(name='my_task')
def my_task(self, *args, **kwargs):
*__do some thing__*
test_tasks.py:
from mock import Mock
def test_my_task():
self = Mock()
self.request.id = 'ci_test'
my_task(self)