Django-kereviz ile birim testi?


82

Django-kereviz projemiz için bir test metodolojisi bulmaya çalışıyorum . Belgelerdeki notları okudum ama gerçekte ne yapacağım konusunda bana iyi bir fikir vermedi. Ben, gerçek cinleri içinde sadece işlevselliği görevlerini test endişe değilim benim kod. Temelde merak ediyorum:

  1. task.delay()Test sırasında nasıl baypas edebiliriz (Ayarı denedim CELERY_ALWAYS_EAGER = Trueama bir fark yaratmadı)?
  2. Ayarları.py gerçekten değiştirmeden önerilen test ayarlarını (en iyi yol buysa) nasıl kullanacağız?
  3. Hala kullanabilir miyiz manage.py testyoksa özel bir koşucu kullanmak zorunda mıyız?

Genel olarak kereviz ile test etmek için herhangi bir ipucu veya püf noktası çok yardımcı olacaktır.


1
ne demek CELERY_ALWAYS_EAGERfark etmez?
asksol

Hala rabbitmq ile iletişim kuramama konusunda hatalar alıyorum.
Jason Webb

Geri dönüşün var mı? Sanırım .delaybir bağlantı kurmaya çalışmaktan başka bir şey olabilir.
asksol

11
Ayar BROKER_BACKEND=memorybu durumda yardımcı olabilir.
asksol

Haklı olduğunu sor. BROKER_BACKEND=memoryonu düzeltti. Bunu bir cevap olarak koyarsanız, doğru olarak işaretleyeceğim.
Jason Webb

Yanıtlar:



72

Override_settings dekoratörünü, tamamlanması için kereviz sonuçları gerektiren testlerde kullanmayı seviyorum.

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())

Tüm testler için bu uygulamak istiyorsanız en anlatıldığı gibi kereviz testi koşucu kullanabilir http://docs.celeryproject.org/en/2.5/django/unit-testing.html temelde (dışında bu aynı ayarları belirleyen BROKER_BACKEND = 'memory').

Ayarlarda:

TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner'

CeleryTestSuiteRunner için kaynağa bakın ve neler olduğu oldukça açık.


1
Bu bile saha yeniden adlandırır ile, kereviz 4 ile işe yaramadı burada
vasiliy

Kereviz 3.1. Kereviz test vakalarımın bu dekoratörle bir ebeveyn sınıfından miras almasını istiyorum. Bu şekilde yalnızca tek bir yerde ihtiyaç duyulur ve içeri girmeye gerek yoktur djcelery.
kontextify

1
Bu, Kereviz 4.4'te harika çalışıyor. ve Django 2.2. Şimdiye kadar karşılaştığım birim testleri çalıştırmak için en iyi yaklaşım.
Erik Kalkoken

18

Burada, apply_asyncyöntemi ortaya çıkaran ve ona yapılan çağrıları kaydeden (dahil Task.delay) test temel sınıfımdan bir alıntı var . Biraz iğrenç, ancak son birkaç aydır kullanıyorum ihtiyaçlarımı karşılamayı başardı.

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)

Bunu test durumlarınızda nasıl kullanacağınıza dair bir "baştan sona" örnek:

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)

4

bunun hala arama sonuçlarında göründüğünü gördüğüm için, ayarlar geçersiz kılıyor

TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner'

Celery Docs'a göre benim için çalıştı


1

2019'da buraya gelen herkes için: görevleri eşzamanlı olarak çağırmak da dahil olmak üzere farklı stratejileri kapsayan bu makaleye göz atın.


1

Yaptığım bu

Myapp.tasks.py içinde şunlar var:

from celery import shared_task

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

Myapp.test_tasks.py içinde:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.