J'essaie de trouver une méthodologie de test pour notre projet Django-celery . J'ai lu les notes dans la documentation , mais cela ne m'a pas donné une bonne idée de ce que je dois réellement faire. Je ne suis pas inquiet de tester les tâches dans les démons réels, juste la fonctionnalité de mon code . Je me demande principalement:
task.delay()
pendant le test (j'ai essayé de définir CELERY_ALWAYS_EAGER = True
mais cela n'a fait aucune différence)?manage.py test
ou devons-nous utiliser un coureur personnalisé?Dans l'ensemble, des conseils ou des astuces pour tester avec le céleri seraient très utiles.
J'aime utiliser le décorateur override_settings sur les tests qui nécessitent des résultats de céleri pour terminer.
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())
Si vous souhaitez appliquer cela à tous les tests, vous pouvez utiliser le lanceur de test de céleri comme décrit sur http://docs.celryproject.org/en/2.5/Django/unit-testing.html qui définit essentiellement ces mêmes paramètres sauf (BROKER_BACKEND = 'memory'
).
Dans les paramètres:
TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner'
Regardez la source de CeleryTestSuiteRunner et c'est assez clair ce qui se passe.
Voici un extrait de ma classe de base de test qui stubs out le apply_async
méthode et enregistre les appels à celle-ci (qui inclut Task.delay
.) C'est un peu dégoûtant, mais il a réussi à répondre à mes besoins au cours des derniers mois, je l'ai utilisé.
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)
Voici un exemple "sur le dessus de la tête" de la façon dont vous l'utiliseriez dans vos cas de test:
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)
puisque je vois toujours cela apparaître dans les résultats de recherche, les paramètres remplacent
TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner'
travaillé pour moi selon Celery Docs
C'est ce que j'ai fait
Dans myapp.tasks.py, j'ai:
from celery import shared_task
@shared_task()
def add(a, b):
return a + b
Dans myapp.test_tasks.py, j'ai:
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
Pour tous ceux qui arrivent ici en 2019: consultez cet article couvrant différentes stratégies, y compris l'appel de tâches de manière synchrone.