让Celery使用Django Test DB

时间:2014-02-28 20:51:27

标签: python django unit-testing celery django-celery

我正在尝试在我的Django应用程序中为一些芹菜任务编写一些单元测试。这些任务将模型ID作为参数,执行一些操作并更新模型。当运行devserver和celery worker时,一切都很好,但是在运行我的测试时,很明显celery任务没有使用在测试运行过程中创建和销毁的django测试数据库。问题是,如何让芹菜使用与我的其他测试相同的临时数据库?

正如您所看到的,我正在使用针对类似问题的每个答案中建议的设置覆盖。

更新:发现不是将对象id传递给任务而是让任务从数据库中获取,如果我只是将对象本身传递给任务,那么测试工作正常,显然没有对任务产生负面影响。任务。所以至少现在,这将是我的修复。

在我的测试中:

class JobTest(TestCase):

    @override_settings(CELERY_ALWAYS_EAGER=True,
                       CELERY_EAGER_PROPAGATES_EXCEPTIONS=True,
                       BROKER_BACKEND='memory')
    def test_Job_Complete(self):
        job = models.Job()
        job.save()
        tasks.do_a_thing(job.id)
        self.assertTrue(job.complete)

在我的任务中:

@celery.task
def do_a_thing(job_id):
    job = models.Job.objects.get(pk=job_id)
    bunch_of_things(job)
    job.complete = True
    job.save()

4 个答案:

答案 0 :(得分:2)

我遇到了类似的问题。以下解决方案是不干净,但它有效。

  1. 创建一个单独的Django设置文件,该文件继承自您的main 一。我们称之为integration_testing.py
  2. 您的文件应如下所示:
    from .settings import *

    DATABASES = { 'default': { 'ENGINE': '<your engine>', 'NAME': 'test_<your database name>', 'USER': <your db user>, 'PASSWORD': <your db password>, 'HOST': <your hostname>, 'PORT': <your port number>, }

  3. 创建一个shell脚本,用于设置环境并启动 芹菜工人:

    #!/usr/bin/env bash

    export DJANGO_SETTINGS_MODULE="YOURPROJECTNAME.settings.integration_testing"

    celery purge -A YOURPROJECTNAME -f && celery worker -A YOURPROJECTNAME -l debug

  4. 如果您以这种方式配置芹菜,则上述情况有效:

    app = Celery('YOURPROJECTNAME')

    app.config_from_object('django.conf:settings', namespace='CELERY')

  5. 在后台运行脚本。

  6. 让所有涉及Celery的测试都继承自TransactionTestCase(或django-rest-framework中的APITransactionTestCase)

  7. 运行使用芹菜的单元测试。任何芹菜任务现在都将使用您的测试数据库。并希望最好。

答案 1 :(得分:1)

您的代码没有明显问题。你不需要经营芹菜工人。通过这些设置,芹菜将同步运行任务,并且实际上不会向您的消息队列发送任何内容。

无论如何,您无法轻松地使用实时芹菜工作者运行测试,因为每个测试都包含在一个事务中,因此即使它们连接到同一个数据库(它们不是),事务总是会被测试和从来没有给工人。

如果您确实需要这样做,请查看this stackoverflow answer

答案 2 :(得分:1)

保证Celery工作程序配置为使用与测试相同的测试数据库的一种方法是spawn the Celery worker inside the test itself。这可以通过在celery.contrib.testing.worker.start_worker的{​​{1}}方法中使用setUpClass来完成。

您还必须使用来自Django的TestCase或来自Rest的SimpleTestCase而不是普通APISimpleTestCase,以便Celery线程和测试线程可以看到彼此的更改制作测试数据库。这些更改在测试结束时仍然被销毁,但除非您在TestCase方法中手动销毁它们,否则它们不会在测试之间销毁。

答案 3 :(得分:0)

我发现将以下内容添加到 conftest.py 有效:

from django.conf import settings

...

@pytest.fixture(scope="session")
def celery_worker_parameters(django_db_setup):
    assert settings.DATABASES["default"]["NAME"].startswith("test_")
    return {}

诀窍是在此处添加 django_db_setup 固定装置,以便在工作器上启用它。

这是对标有以下标记的测试的测试:

@pytest.mark.django_db(transaction=True)
@pytest.mark.celery()
def test_something(celery_worker):
    ...