Python 用django芹菜进行单元测试?

Python 用django芹菜进行单元测试?,python,django,unit-testing,celery,Python,Django,Unit Testing,Celery,我正试图为我们的项目提出一种测试方法。我已经读了报纸上的笔记,但它没有给我一个好主意,告诉我该怎么做。我不担心在实际的守护进程中测试任务,只担心我的代码的功能。我主要想知道: 在测试过程中,我们如何绕过task.delay()(我试着设置芹菜\u ALWAYS\u EAGER=True,但没什么区别) 我们如何使用推荐的测试设置(如果这是最好的方法),而不实际更改我们的设置.py 我们仍然可以使用manage.py test还是必须使用自定义的运行程序 总的来说,任何关于芹菜测试的提示或提示都会

我正试图为我们的项目提出一种测试方法。我已经读了报纸上的笔记,但它没有给我一个好主意,告诉我该怎么做。我不担心在实际的守护进程中测试任务,只担心我的代码的功能。我主要想知道:

  • 在测试过程中,我们如何绕过
    task.delay()
    (我试着设置
    芹菜\u ALWAYS\u EAGER=True
    ,但没什么区别)
  • 我们如何使用推荐的测试设置(如果这是最好的方法),而不实际更改我们的设置.py
  • 我们仍然可以使用
    manage.py test
    还是必须使用自定义的运行程序

  • 总的来说,任何关于芹菜测试的提示或提示都会非常有用。

    这里是我的测试基类的一个摘录,它删除了
    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)
    
    下面是一个“从头到脚”的示例,说明如何在测试用例中使用它:

    mymodule.py

    from my_tasks import SomeTask
    
    def run_some_task(should_run):
        if should_run:
            SomeTask.delay(1, some_kwarg=2)
    
    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)
    
    test\u mymodule.py

    from my_tasks import SomeTask
    
    def run_some_task(should_run):
        if should_run:
            SomeTask.delay(1, some_kwarg=2)
    
    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)
    
    尝试设置:

    BROKER_BACKEND = 'memory'
    

    (感谢的评论。)

    我喜欢在需要芹菜结果才能完成的测试中使用覆盖设置装饰器

    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())
    
    如果您想将此应用于所有测试,可以使用芹菜测试运行程序(如上所述),它基本上设置了这些相同的设置,除了(
    BROKER\u BACKEND='memory'

    在设置中:

    TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner'
    

    查看CeleryTestSuiteRunner的源代码,很清楚发生了什么事。

    因为我在搜索结果中仍然看到这一点,设置会覆盖

    TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner'
    

    根据《2019年来这里的每个人》为我工作:结帐涵盖不同的策略,包括同步调用任务。

    我就是这么做的

    在myapp.tasks.py中,我有:

    from celery import shared_task
    
    @shared_task()
    def add(a, b):
        return a + b
    
    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
    
    在myapp.test_tasks.py中,我有:

    from celery import shared_task
    
    @shared_task()
    def add(a, b):
        return a + b
    
    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
    

    你是什么意思?
    芹菜\u ALWAYS\u Earneg
    没有区别?我仍然会遇到无法联系rabbitmq的错误。你有回溯吗?我想除了
    .delay
    之外,可能还有其他东西在试图建立连接。设置
    BROKER\u BACKEND=memory
    在这种情况下会有所帮助。问问你是对的
    BROKER\u BACKEND=memory
    修复了它。如果你把它作为一个答案,我会把它标记为正确的。我相信当芹菜总是渴望设置时,这不再是必要的。你找到芹菜4的解决方案了吗?这对芹菜4不起作用,即使是芹菜3.1上的字段重命名。我只是让我的芹菜测试用例通过这个装饰器从父类继承。这样一来,它只需要放在一个地方,而不需要拉入芹菜。这在芹菜4.4上非常有效。和Django 2.2。到目前为止,我遇到的运行单元测试的最佳方法。