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
,但没什么区别)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。到目前为止,我遇到的运行单元测试的最佳方法。