[Django]-Python: Mock doesn't work inside celery task

7👍

✅

I found a problem and it was pretty silly. Described here and Here:

The basic principle is that you patch where an object is looked up, which is not necessarily the same place as where it is defined.

I need to change:

@mock.patch('django.core.mail.mail_managers')

with

@mock.patch('path.to.tasks.mail_managers')

4👍

Testing the behavior of asynchronous tasks directly from the code that uses them can be tricky. One reason is that the test may execute assertions even before the task actually runs, which will likely give you false positives. What I do in cases like this is to break the testing into two steps:

  1. Mocking the task and testing that it is called when it has to be called and with the expected arguments.
  2. Test the task as a standalone function and by executing it as a normal function, i.e. without the need of the celery server.

To illustrate, this could be like:

# views.py
from path.to.tasks import my_task


def my_view(requtest):
    # do stuff
    my_task.delay('foo', 'bar')
    return HttpResponse('whatever')


# test_my_task.py
from views import my_view
from path.to.tasks import my_task


class MyTest(TestCase):
    @mock.patch('path.to.tasks.my_task')
    def test_my_task_is_called(self, mocked_task):
        client = Client()
        client.get('/')
        my_task.assert_called_with('foo', 'bar')

    def test_my_task_works(self):
        my_task('foo', 'bar')  # note I don't use .delay(...), .apply_async(...), etc
        assert 'my task did what I expected it to do'

This way you can test that your implementing code behaves correctly in regards to your task and that the task behaves correctly once it’s called as expected.

I hope it’s useful! 🙂

Leave a comment