简体   繁体   English

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

[英]Unit testing with django-celery?

I am trying to come up with a testing methodology for our django-celery project. 我正在尝试为我们的django-celery项目提出测试方法。 I have read the notes in the documentation , but it didn't give me a good idea of what to actually do. 我已经阅读了文档中的注释,但它并没有让我对实际操作有什么了解。 I am not worried about testing the tasks in the actual daemons, just the functionality of my code. 我并不担心测试实际守护进程中的任务,只是我的代码的功能。 Mainly I am wondering: 主要是我想知道:

  1. How can we bypass task.delay() during the test (I tried setting CELERY_ALWAYS_EAGER = True but it made no difference)? 我们如何在测试期间绕过task.delay() (我尝试设置CELERY_ALWAYS_EAGER = True但它没有区别)?
  2. How do we use the test settings that are recommended (if that is the best way) without actually changing our settings.py? 我们如何在不实际更改settings.py的情况下使用推荐的测试设置(如果这是最佳方式)?
  3. Can we still use manage.py test or do we have to use a custom runner? 我们还可以使用manage.py test吗?还是我们必须使用自定义跑步者?

Overall any hints or tips for testing with celery would be very helpful. 总的来说,使用芹菜进行测试的任何提示或技巧都会非常有用。

I like to use the override_settings decorator on tests which need celery results to complete. 我喜欢在需要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())

If you want to apply this to all tests you can use the celery test runner as described at http://docs.celeryproject.org/en/2.5/django/unit-testing.html which basically sets these same settings except ( BROKER_BACKEND = 'memory' ). 如果你想将它应用于所有测试,你可以使用http://docs.celeryproject.org/en/2.5/django/unit-testing.html中描述的celery测试运行器,它基本上设置了这些相同的设置,除了( BROKER_BACKEND = 'memory' )。

In settings: 在设置中:

TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner'

Look at the source for CeleryTestSuiteRunner and it's pretty clear what's happening. 看看CeleryTestSuiteRunner的来源,很明显发生了什么。

Try setting: 尝试设置:

BROKER_BACKEND = 'memory'

(Thanks to asksol 's comment.) (感谢asksol的评论。)

Here's an excerpt from my testing base class that stubs out the apply_async method and records to the calls to it (which includes Task.delay .) It's a little gross, but it's managed to fit my needs over the past few months I've been using it. 这是我的测试基类的一个摘录, 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)

Here's an "off the top of the head" example of how you'd use it in your test cases: 以下是您在测试用例中如何使用它的“头顶”示例:

mymodule.py

from my_tasks import SomeTask

def run_some_task(should_run):
    if should_run:
        SomeTask.delay(1, some_kwarg=2)

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)

since I still see this come up in search results, settings override with 因为我仍然看到这出现在搜索结果中,设置覆盖了

TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner'

worked for me as per Celery Docs 根据Celery Docs为我工作

对于2019年来到这里的每个人:查看本文涵盖不同的策略,包括同步调用任务。

This is what I did 这就是我做的

Inside myapp.tasks.py I have: 在myapp.tasks.py里面我有:

from celery import shared_task

@shared_task()
def add(a, b):
    return a + b

Inside myapp.test_tasks.py I have: 在myapp.test_tasks.py里面我有:

from django.test import TestCase, override_settings
from myapp.tasks import add


class TasksTestCase(TestCase):

    def setUp(self):
        ...

    @override_settings(CELERY_TASK_ALWAYS_EAGER=True,CELERY_TASK_EAGER_PROPOGATES=True)
    def test_create_sections(self):
        result= add.delay(1,2)
        assert result.successful() == True
        assert result.get() == 3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM