Django-celery プロジェクトのテスト方法論を考えています。 documentation の注意事項を読みましたが、実際に何をすべきかについての良い考えを与えませんでした。実際のデーモンでタスクをテストするのではなく、myコードの機能だけを心配する必要はありません。主に私は疑問に思っています:
task.delay()
をバイパスするにはどうすればよいですか(CELERY_ALWAYS_EAGER = True
を設定しようとしましたが、違いはありませんでした)。manage.py test
を引き続き使用できますか、またはカスタムランナーを使用する必要がありますか?全体的に、セロリでテストするためのヒントやヒントは非常に役立ちます。
セロリの結果を完了する必要があるテストで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())
これをすべてのテストに適用する場合は、 http://docs.celeryproject.org/en/2.5/Django/unit-testing.html で説明されているセロリテストランナーを使用できます。 (BROKER_BACKEND = 'memory'
)を除くこれらの同じ設定。
設定で:
TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner'
CeleryTestSuiteRunnerのソースを見ると、何が起こっているのかがかなり明確です。
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)
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)
これはまだ検索結果に表示されるので、設定は
TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner'
Celery Docs に従って私のために働いた
これは私がやったことです
Myapp.tasks.pyの中には:
from celery import shared_task
@shared_task()
def add(a, b):
return a + b
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
2019年にここに来るすべての人のために:checkout この記事 タスクの同期呼び出しを含むさまざまな戦略をカバーしています。