आप सेलरी कार्य का परीक्षण कैसे करते हैं?


106

सेलेरी प्रलेखन में सेलेरी के परीक्षण का उल्लेख किया गया है, लेकिन अगर आप Django का उपयोग नहीं कर रहे हैं, तो एक अजवाइन कार्य का परीक्षण कैसे करें, यह नहीं बताता। आप यह कैसे करते हैं?

जवाबों:


61

वहाँ किसी भी unittest lib का उपयोग करके समकालिक रूप से कार्यों का परीक्षण करना संभव है। अजवाइन के कार्यों के साथ काम करते समय मैं 2 अलग-अलग परीक्षण सत्र करता हूं। पहला वाला (जैसा कि मैं सुझाव दे रहा हूं) पूरी तरह से समकालिक है और ऐसा होना चाहिए जो यह सुनिश्चित करता है कि एल्गोरिथ्म वही करता है जो उसे करना चाहिए। दूसरा सत्र पूरी प्रणाली (ब्रोकर सहित) का उपयोग करता है और यह सुनिश्चित करता है कि मुझे क्रमबद्धता मुद्दे या कोई अन्य वितरण, संचार समस्या नहीं है।

इसलिए:

from celery import Celery

celery = Celery()

@celery.task
def add(x, y):
    return x + y

और आपका परीक्षण:

from nose.tools import eq_

def test_add_task():
    rst = add.apply(args=(4, 4)).get()
    eq_(rst, 8)

उम्मीद है की वो मदद करदे!


1
यह उन कार्यों को छोड़कर काम करता है, जो एक HttpDispatchTask - docs.celeryproject.org/en/latest/userguide/remote-tasks.html का उपयोग करते हैं, जहां मुझे celery.conf .CELERY_ALWAYS_EAGER = True सेट करना होता है, लेकिन यह भी सेट करने के साथ ही celery.conf.CELERY ('celery.task.http') परीक्षण NotRegistered के साथ विफल रहता है: celery.task.http.HttpDispatchTask
davidmytton

अजीब, क्या आप सुनिश्चित हैं कि आप कुछ आयात मुद्दे नहीं रख रहे हैं? यह परीक्षण काम करता है (ध्यान दें कि मैं प्रतिक्रिया को फीका कर रहा हूं, इसलिए यह अजवाइन की अपेक्षा करता है)। इसके अलावा, CELERY_IMPORTS में परिभाषित मॉड्यूल को श्रमिकों के आरंभ के दौरान आयात किया जाएगा , इससे बचने के लिए मैं आपको कॉल करने का सुझाव देता हूं celery.loader.import_default_modules()
FlaPer87

मैं आपको यहां एक बार देखने का सुझाव भी दूंगा । यह http अनुरोध का मजाक उड़ाता है। डनो पता है कि क्या यह मदद करता है, मुझे लगता है कि आप एक ऐसी सेवा का परीक्षण करना चाहते हैं जो ऊपर और चल रही है, क्या आप नहीं?
FlaPer87

52

मैं इसका उपयोग करता हूं:

with mock.patch('celeryconfig.CELERY_ALWAYS_EAGER', True, create=True):
    ...

डॉक्स: http://docs.celeryproject.org/en/3.1/configuration.html#celery-aler-nger

CELERY_ALWAYS_EAGER आपको अपने कार्य को सिंक्रोनाइज़ करने देता है, और आपको अजवाइन सर्वर की आवश्यकता नहीं है।


1
मुझे लगता है कि यह पुराना है - मुझे लगता है ImportError: No module named celeryconfig
डेनिथ

7
मेरा मानना ​​है कि ऊपर मान लिया गया है कि मॉड्यूल celeryconfig.pyकिसी के पैकेज में मौजूद है। Docs.celeryproject.org/en/latest/getting-started/… देखें ।
कामिल सिंडी

1
मुझे पता है कि यह पुराना है, लेकिन क्या आप addएक TestCaseकक्षा के भीतर ओपी के प्रश्न से कार्यों को शुरू करने के लिए एक पूर्ण उदाहरण प्रदान कर सकते हैं ?
कुरुपूप्स

@ MaxChrétien क्षमा करें, मैं पूर्ण उदाहरण प्रदान नहीं कर सकता, क्योंकि मैं अजवाइन का उपयोग नहीं करता। यदि आपके पास पर्याप्त प्रतिष्ठा बिंदु हैं, तो आप मेरे प्रश्न को संपादित कर सकते हैं। यदि आपके पास पर्याप्त नहीं है, तो कृपया मुझे बताएं कि मुझे इस उत्तर में क्या कॉपी + पेस्ट करना चाहिए।
गुप्ताई

1
@ miken32 धन्यवाद। जैसा कि हाल ही में दिए गए उत्तर ने किसी भी तरह से उस समस्या से निपटा है जिसकी मैं मदद करना चाहता था, मैंने अभी एक टिप्पणी छोड़ दी है कि CELERY_TASK_ALWAYS_EAGERयूनिट परीक्षण के लिए 4.0 डॉक्सेज के आधिकारिक अधिकार का उपयोग करता है ।
krassowski

33

निर्भर करता है कि वास्तव में आप क्या परीक्षण करना चाहते हैं।

  • सीधे कार्य कोड का परीक्षण करें। अपने यूनिट परीक्षणों से "task.delay (...)" बस "कार्य (...)" कॉल न करें।
  • CELERY_ALWAYS_EAGER का उपयोग करें । यह आपके कार्यों को तुरंत उस बिंदु पर बुलाया जाएगा जो आप कहते हैं कि "task.delay (...)", इसलिए आप पूरे पथ का परीक्षण कर सकते हैं (लेकिन कोई अतुल्यकालिक व्यवहार नहीं)।

24

अध्याय परीक्षा

import unittest

from myproject.myapp import celeryapp

class TestMyCeleryWorker(unittest.TestCase):

  def setUp(self):
      celeryapp.conf.update(CELERY_ALWAYS_EAGER=True)

py.test जुड़नार

# conftest.py
from myproject.myapp import celeryapp

@pytest.fixture(scope='module')
def celery_app(request):
    celeryapp.conf.update(CELERY_ALWAYS_EAGER=True)
    return celeryapp

# test_tasks.py
def test_some_task(celery_app):
    ...

परिशिष्ट: send_task सम्मान को उत्सुक बनाएं

from celery import current_app

def send_task(name, args=(), kwargs={}, **opts):
    # https://github.com/celery/celery/issues/581
    task = current_app.tasks[name]
    return task.apply(args, kwargs, **opts)

current_app.send_task = send_task

22

अजवाइन 4 पर उन लोगों के लिए:

@override_settings(CELERY_TASK_ALWAYS_EAGER=True)

क्योंकि सेटिंग्स के नाम बदल दिए गए हैं और अपग्रेड करने का विकल्प चुनने पर अपडेट करने की जरूरत है, देखें

https://docs.celeryproject.org/en/latest/history/whatsnew-4.0.html?highlight=what%20is%20new#lowercase-setting-names


11
आधिकारिक डॉक्स के अनुसार , "task_always_eager" (पहले "CELERY_ALWAYS_EAGER") का उपयोग इकाई परीक्षण के लिए उपयुक्त नहीं है। इसके बजाय वे कुछ और प्रपोज़ करते हैं, आपके सेलरी ऐप को यूनिट करने के शानदार तरीके।
krassowski

4
मैं सिर्फ इतना जोड़ता हूँ कि आप अपने यूनिट परीक्षणों में उत्सुक कार्य क्यों नहीं करना चाहते हैं, क्योंकि तब आप परीक्षण नहीं कर रहे हैं जैसे कि मानकों का क्रमांकन जो उत्पादन में कोड का उपयोग करने के बाद होगा।
डैम

15

सेलेरी 3.0 के रूप में , DjangoCELERY_ALWAYS_EAGER में सेट करने का एक तरीका है:

from django.test import TestCase, override_settings

from .foo import foo_celery_task

class MyTest(TestCase):

    @override_settings(CELERY_ALWAYS_EAGER=True)
    def test_foo(self):
        self.assertTrue(foo_celery_task.delay())

7

अजवाइन v4.0 के बाद से , py.test जुड़नार केवल परीक्षण के लिए अजवाइन कार्यकर्ता शुरू करने के लिए प्रदान किए जाते हैं और जब भी बंद होते हैं:

def test_myfunc_is_executed(celery_session_worker):
    # celery_session_worker: <Worker: gen93553@gnpill.local (running)>
    assert myfunc.delay().wait(3)

Http://docs.celeryproject.org/en/latest/userguide/testing.html#py-test पर वर्णित अन्य जुड़नार के बीच , आप celery_configइस तरह से स्थिरता को फिर से परिभाषित करके अजवाइन के डिफ़ॉल्ट विकल्पों को बदल सकते हैं :

@pytest.fixture(scope='session')
def celery_config():
    return {
        'accept_content': ['json', 'pickle'],
        'result_serializer': 'pickle',
    }

डिफ़ॉल्ट रूप से, परीक्षण कर्मचारी इन-मेमोरी ब्रोकर और परिणाम बैकएंड का उपयोग करता है। विशिष्ट विशेषताओं का परीक्षण नहीं करने पर स्थानीय रेडिस या रैबिटमक्यू का उपयोग करने की आवश्यकता नहीं है।


प्रिय downvoter, क्या आप साझा करना चाहेंगे कि यह एक बुरा जवाब क्यों है? साभार
अलंजाद्स

2
मेरे लिए काम नहीं किया, परीक्षण सूट बस लटका हुआ है। क्या आप कुछ और संदर्भ प्रदान कर सकते हैं? (हालांकि मैंने अभी तक वोट नहीं दिया है;))।
द्वितीया_

मेरे मामले में मुझे स्पष्ट रूप से मेमोरी ब्रोकर और कैश + मेमोरी बैकेंड का उपयोग करने के लिए celey_config स्थिरता सेट करना था
sanzoghenzo

5

pytest का उपयोग करते हुए संदर्भ

def test_add(celery_worker):
    mytask.delay()

यदि आप फ्लास्क का उपयोग करते हैं, तो एप्लिकेशन कॉन्फिगर सेट करें

    CELERY_BROKER_URL = 'memory://'
    CELERY_RESULT_BACKEND = 'cache+memory://'

और में conftest.py

@pytest.fixture
def app():
    yield app   # Your actual Flask application

@pytest.fixture
def celery_app(app):
    from celery.contrib.testing import tasks   # need it
    yield celery_app    # Your actual Flask-Celery application

2

मेरे मामले में (और मैं कई अन्य लोगों को मानता हूं), मैं चाहता था कि किसी भी काम का आंतरिक तर्क pytest का उपयोग करके किया जाए।

टी एल; डॉ; सब कुछ खत्म कर दिया ( विकल्प 2 )


उदाहरण उपयोग मामला :

proj/tasks.py

@shared_task(bind=True)
def add_task(self, a, b):
    return a+b;

tests/test_tasks.py

from proj import add_task

def test_add():
    assert add_task(1, 2) == 3, '1 + 2 should equal 3'

लेकिन, चूंकि shared_taskडेकोरेटर अजवाइन के आंतरिक तर्क का एक बहुत कुछ करता है, यह वास्तव में एक इकाई परीक्षण नहीं है।

तो, मेरे लिए, 2 विकल्प थे:

विकल्प 1: आंतरिक तर्क अलग करें

proj/tasks_logic.py

def internal_add(a, b):
    return a + b;

proj/tasks.py

from .tasks_logic import internal_add

@shared_task(bind=True)
def add_task(self, a, b):
    return internal_add(a, b);

यह बहुत ही अजीब लगता है, और इसे कम पठनीय बनाने के अलावा, इसे मैन्युअल रूप से उन विशेषताओं को निकालने और पास करने की आवश्यकता होती है जो अनुरोध का हिस्सा हैं, उदाहरण के लिए task_idयदि आपको इसकी आवश्यकता है, जो तर्क को कम शुद्ध बनाते हैं।

विकल्प 2: नकली
अजवाइन के पत्तों का मजाक उड़ाता है

tests/__init__.py

# noinspection PyUnresolvedReferences
from celery import shared_task

from mock import patch


def mock_signature(**kwargs):
    return {}


def mocked_shared_task(*decorator_args, **decorator_kwargs):
    def mocked_shared_decorator(func):
        func.signature = func.si = func.s = mock_signature
        return func

    return mocked_shared_decorator

patch('celery.shared_task', mocked_shared_task).start()

जो तब मुझे अनुरोध ऑब्जेक्ट (फिर से, जैसे आईडी, या रिट्रीस काउंटर, अनुरोध से चीजों की आवश्यकता होती है) का मजाक उड़ाने की अनुमति देता है।

tests/test_tasks.py

from proj import add_task

class MockedRequest:
    def __init__(self, id=None):
        self.id = id or 1


class MockedTask:
    def __init__(self, id=None):
        self.request = MockedRequest(id=id)


def test_add():
    mocked_task = MockedTask(id=3)
    assert add_task(mocked_task, 1, 2) == 3, '1 + 2 should equal 3'

यह समाधान बहुत अधिक मैनुअल है, लेकिन, यह मुझे नियंत्रण देता है कि मुझे वास्तव में यूनिट टेस्ट करने की आवश्यकता है , खुद को दोहराए बिना और अजवाइन के दायरे को खोए बिना।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.