Python:模拟功能在芹菜任务中不起作用 - python

This question already has answers here:

Why python mock patch doesn't work?

(2个答案)

5年前关闭。

我想使用python mock库来测试我的Django应用程序发送电子邮件。

测试代码:

# tests.py
from django.test import TestCase

class MyTestCase(TestCase):

    @mock.patch('django.core.mail.mail_managers')
    def test_canceled_wo_claiming(self, mocked_mail_managers):
        client = Client()
        client.get('/')
        print(mocked_mail_managers.called)
        mocked_mail_managers.assert_called_with('Hi, managers!', 'Message Body')

第一个例子-没有任务

# views.py
from django.views.generic import View
from django.core.mail import mail_managers

class MyView(View):

    def get(self, request):
        mail_managers('Hi, managers!', 'Message Body')
        return HttpResponse('Hello!')

第二个例子-有任务

# views.py
from django.views.generic import View
from . import tasks

class MyView(View):
    def get(self, request):
        tasks.notify.apply_async()
        return HttpResponse('Hello!')


# tasks.py
from celery import shared_task
from django.core.mail import mail_managers

@shared_task
def notify():
    mail_managers('Hi, managers!', 'Message Body')

第一个示例正常工作,第二个示例失败,并出现Not called异常。

我的设置:

# Celery
BROKEN_URL = 'memory://'
BROKER_BACKEND = 'memory'

CELERY_ALWAYS_EAGER = True
CELERY_EAGER_PROPAGATES_EXCEPTIONS = True
TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner'

是否可以执行这样的集成测试,或者解决此问题的唯一方法是将测试分为两个?

python大神给出的解决方案

直接从使用异步任务的代码中测试它们的行为可能很棘手。原因之一是测试甚至可能在任务实际运行之前就执行断言,这可能会给您带来误报。在这种情况下,我要做的就是将测试分为两个步骤:

模拟任务并在必须使用预期参数调用它时对其进行测试。
将任务作为独立功能进行测试,并通过将其作为普通功能执行(即不需要celery服务器)来进行测试。

为了说明这一点,可能是这样的:

# views.py
from path.to.tasks import my_task


def my_view(requtest):
    # do stuff
    my_task.delay('foo', 'bar')
    return HttpResponse('whatever')


# test_my_task.py
from views import my_view
from path.to.tasks import my_task


class MyTest(TestCase):
    @mock.patch('path.to.tasks.my_task')
    def test_my_task_is_called(self, mocked_task):
        client = Client()
        client.get('/')
        my_task.assert_called_with('foo', 'bar')

    def test_my_task_works(self):
        my_task('foo', 'bar')  # note I don't use .delay(...), .apply_async(...), etc
        assert 'my task did what I expected it to do'

这样,您可以测试您的实现代码就您的任务而言是否正确运行,以及一旦按预期方式调用该任务后,它便可以正确运行。

我希望它有用! 🙂