Подтвердить что ты не робот

Использование mock для исправления задачи сельдерея в модульных тестах Django

Я пытаюсь использовать библиотеку python mock для исправления задачи Celery, которая запускается, когда модель сохраняется в моем приложении django, чтобы убедиться, что она правильно называется.

В принципе задача задается внутри myapp.tasks и импортируется в верхней части моего model.py файла следующим образом:

from .tasks import mytask

... и затем пробегает save() внутри модели, используя mytask.delay(foo, bar). Пока все хорошо - отлично работает, когда я на самом деле запускаю Celerydd и т.д.

Я хочу построить unit test, который издевается над задачей, просто чтобы проверить, что она вызвана с правильными аргументами, и на самом деле не пытается запустить задачу Celery когда-либо.

Итак, в тестовом файле у меня есть что-то вроде этого внутри стандартной TestCase:

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)

... но он никогда не вызывается/всегда false. Я попробовал различные инкарнации (вместо исправления myapp.models.mytask и проверки, если вместо этого был вызван mock_task.delay. Я собрал из mock docs, что путь импорта имеет решающее значение, а googling говорит мне, что это должен быть путь, как он отображается внутри тестируемого модуля (который будет myapp.models.mytask.delay, а не myapp.tasks.mytask.delay, если я его правильно пойму).

Где я здесь ошибаюсь? Есть ли определенные трудности в исправлении задач Сельдерея? Могу ли я запланировать celery.task (который используется как декоратор для mytask) вместо?

4b9b3361

Ответ 1

Проблема, с которой вы сталкиваетесь, не связана с тем, что это задача сельдерея. Вы просто ошибаетесь.;)

В частности, вам нужно выяснить, какой вид или другой файл импортирует "mytask" и исправляет его там, поэтому соответствующая строка будет выглядеть так:

with patch('myapp.myview.mytask.delay') as mock_task:

Здесь есть еще несколько привкус:

http://www.voidspace.org.uk/python/mock/patch.html#where-to-patch

Ответ 2

Декоратор @task заменяет функцию объектом Task (см. документация). Если вы издеваетесь над самой задачей, вы замените (несколько волшебный) объект Task на MagicMock, и он не будет планировать задачу вообще. Вместо этого издевайтесь над методом Task object 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)