I have a task 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
How can I mock the self.request.id
attribute? I am already patching everything and calling directly the task rather than using .delay/.apply_async
, but the value of self.request.id
seems to be None
(as I am doing real interactions with DB, it is making the test fail, etc…).
For the reference, I'm using Django as a framework, but I think that this problem is just the same, no matter the environment you're using.
Disclaimer: Well, I do not think it was documented somewhere and this answer might be implementation-dependent.
Celery wraps his tasks into celery.Task
instances, I do not know if it swaps the celery.Task.run
method by the user task function or whatever.
But, when you call a task directly, you call __call__
and it'll push a context which will contain the task ID, etc…
So the idea is to bypass __call__
and Celery usual workings, first:
foobar.push_request(id=1)
for example.foobar.run(*args, **kwargs)
.Example:
@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)
You can call the task synchronously using
task = foobar.s(<args>).apply()
This will assign a unique task ID, so the value will not be None and your code will run. Then you can check the results as part of your test.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With