Search code examples
pythonmockingcelerypython-unittestpython-mock

Function called by a Celery task has no calls when patched in a unit test?


Consider the following tasks.py module (adapted from http://docs.celeryproject.org/en/latest/getting-started/first-steps-with-celery.html#first-steps):

import logging
import sys

from celery import Celery

app = Celery('tasks', broker='pyamqp://guest@localhost//')


@app.task
def add(x, y):
    logging.info(f"Adding {x} and {y}...")
    return x + y


def call_add(x, y):
    add.delay(x, y)

In the same directory, I have a test_tasks.py test module which reads

from unittest.mock import patch

import tasks


@patch('logging.info')
def test_adder(info_mock):
    tasks.call_add(1, 2)

    info_mock.assert_not_called()

This test passes (if I run it with pytest test_tasks.py), but I'm not sure why info_mock was not called? I would expect the following assertion to pass

info_mock.assert_called_with("Adding 1 and 2...")

Why is logging.info not called through tasks.call_add() in this example? It seems to me to be equivalent to the example given in http://docs.celeryproject.org/en/latest/userguide/testing.html.


Solution

  • Make sure to run tests directly in the same process when running unit-tests.

    Celery makes it very simple to keep same APIs while running the task "in-sync" and skip the broken/worker part.

    app = Celery('tasks', broker='pyamqp://guest@localhost//', task_always_eager=True)
    

    http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-always-eager