使用django-芹菜进行单元测试?

Jas*_*ebb 79 python django unit-testing celery

我正在尝试为我们的django-celery项目提出测试方法.我已经阅读了文档中的注释,但它并没有让我对实际操作有什么了解.我并不担心测试实际守护进程中的任务,只是我的代码的功能.主要是我想知道:

  1. 我们如何task.delay()在测试期间绕过(我尝试过设置,CELERY_ALWAYS_EAGER = True但没有区别)?
  2. 我们如何在不实际更改settings.py的情况下使用推荐的测试设置(如果这是最佳方式)?
  3. 我们还可以使用manage.py test或者我们必须使用自定义跑步者吗?

总的来说,使用芹菜进行测试的任何提示或技巧都会非常有用.

jos*_*hua 67

我喜欢在需要celery结果的测试中使用override_settings装饰器.

from django.test import TestCase
from django.test.utils import override_settings
from myapp.tasks import mytask

class AddTestCase(TestCase):

    @override_settings(CELERY_EAGER_PROPAGATES_EXCEPTIONS=True,
                       CELERY_ALWAYS_EAGER=True,
                       BROKER_BACKEND='memory')
    def test_mytask(self):
        result = mytask.delay()
        self.assertTrue(result.successful())
Run Code Online (Sandbox Code Playgroud)

如果要将其应用于所有测试,可以使用http://docs.celeryproject.org/en/2.5/django/unit-testing.html中描述的芹菜测试运行器,它基本上设置了除(BROKER_BACKEND = 'memory')之外的相同设置.

在设置中:

TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner'
Run Code Online (Sandbox Code Playgroud)

看看CeleryTestSuiteRunner的来源,很明显发生了什么.

  • 这不适用于 celery 4,即使字段从 [here](http://docs.celeryproject.org/en/4.0/userguide/configuration.html#new-lowercase-settings) 重命名 (2认同)

a p*_*erd 42

尝试设置:

BROKER_BACKEND = 'memory'
Run Code Online (Sandbox Code Playgroud)

(感谢asksol的评论.)

  • 我相信在设置CELERY_ALWAYS_EAGER时不再需要这样做. (6认同)
  • 你有没有找到芹菜4的解决方案? (2认同)

Sam*_*lan 16

这是我的测试基类的摘录,它将apply_async方法和记录存根到对它的调用(包括Task.delay.)这有点粗略,但它已经设法满足我过去几个月我一直在使用它的需求.

from django.test import TestCase
from celery.task.base import Task
# For recent versions, Task has been moved to celery.task.app:
# from celery.app.task import Task
# See http://docs.celeryproject.org/en/latest/reference/celery.app.task.html

class CeleryTestCaseBase(TestCase):

    def setUp(self):
        super(CeleryTestCaseBase, self).setUp()
        self.applied_tasks = []

        self.task_apply_async_orig = Task.apply_async

        @classmethod
        def new_apply_async(task_class, args=None, kwargs=None, **options):
            self.handle_apply_async(task_class, args, kwargs, **options)

        # monkey patch the regular apply_sync with our method
        Task.apply_async = new_apply_async

    def tearDown(self):
        super(CeleryTestCaseBase, self).tearDown()

        # Reset the monkey patch to the original method
        Task.apply_async = self.task_apply_async_orig

    def handle_apply_async(self, task_class, args=None, kwargs=None, **options):
        self.applied_tasks.append((task_class, tuple(args), kwargs))

    def assert_task_sent(self, task_class, *args, **kwargs):
        was_sent = any(task_class == task[0] and args == task[1] and kwargs == task[2]
                       for task in self.applied_tasks)
        self.assertTrue(was_sent, 'Task not called w/class %s and args %s' % (task_class, args))

    def assert_task_not_sent(self, task_class):
        was_sent = any(task_class == task[0] for task in self.applied_tasks)
        self.assertFalse(was_sent, 'Task was not expected to be called, but was.  Applied tasks: %s' %                 self.applied_tasks)
Run Code Online (Sandbox Code Playgroud)

以下是您在测试用例中如何使用它的"头顶"示例:

mymodule.py

from my_tasks import SomeTask

def run_some_task(should_run):
    if should_run:
        SomeTask.delay(1, some_kwarg=2)
Run Code Online (Sandbox Code Playgroud)

test_mymodule.py

class RunSomeTaskTest(CeleryTestCaseBase):
    def test_should_run(self):
        run_some_task(should_run=True)
        self.assert_task_sent(SomeTask, 1, some_kwarg=2)

    def test_should_not_run(self):
        run_some_task(should_run=False)
        self.assert_task_not_sent(SomeTask)
Run Code Online (Sandbox Code Playgroud)