如何测试执行芹菜任务后是否发送电子邮件



我正在使用django 1.10和芹菜4.1

我有一个shared_task,它将电子邮件发送给用户。

# myapp/tasks.py
@shared_task
def notify_user(user_id):
    # TODO: send email and do other stuff here
    user = get_object_or_404(User, pk=user_id)
    send_mail(
        'Subject',
        'Body',
        'from@example.com',
        [user.email],
    )

我有另一个文件包含一个函数,该函数将该任务放入队列中。

# myapp/utils.py
# ...
def update_queue(self):
    # increment no_of_used_referrals by 1
    if no_of_used_referrals == 5:
        notify_user.apply_async((self.user_id,))
    else:
        notify_user.apply_async((self.user_id,), eta=new_eta)

现在,我正在尝试测试是否拨打update_queue()(所有必需的支票通过)执行时将电子邮件发送给用户。

我试图做以下操作:

# myapp/tests.py
def update_queue_should_call_notify_user_immediately_after_five_referrals_were_used(self):
    with unittest.mock.patch('myapp.tasks.notify_user.apply_async') as notify_user_mock:
        # ...
        for _ in range(5):
            entry.update_queue()
        self.assertTrue(notify_user_mock.called)
        notify_user_mock.assert_called_with((user_id,))
    # TODO: check if email was sent
    # I tried using : 
    # self.assertEqual(len(mail.outbox), 1) 
    # but it fails with error saying 0 != 1
def test_notify_user_should_send_an_email(self):
    notify_user.apply_async((user_id,))
    # I tried using:
    # self.assertEqual(len(mail.outbox), 1)
    # but it fails with error saying 0 != 1

我已经在项目设置中设置了EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'

有人可以告诉我我在做什么以及如何正确测试这种情况是什么问题?

编辑我已经更新了我排除在嘲笑的代码 - @DanielRoseman建议。

edit2 请参阅上面更新的文件。

我正在模拟推荐系统。一旦使用了与特定用户关联的5个推荐链接,用户将获得其个人资料的一些不错的功能。否则,他们必须等待特定时间,我使用eta参数在apply_async上进行设置。

每次我致电update_queue时,我都会检查参考数量是否等于5(请参阅上面的更新代码)。

  • 如果是 - 我想立即致电notify_user,而无需传递eta参数值。
  • 如果不是 - 我会增加使用的推荐链接的数量,撤销旧notify_user任务,创建新的notify_user任务,使用新的eta参数值。

为了测试我在循环中模拟该行为,我想测试5次迭代(等于5个使用的转介链接)是否发送给用户(用于测试目的,我使用In-In-电子邮件的内存后端)。

我把它放在这里面临同样问题的人。

我已经用

解决了
TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner'

https://stackoverflow.com/a/46531472/7396169

我认为此解决方案适用于单位测试。

tasks.py

from django.core.mail import EmailMessage
from django.template.loader import render_to_string
from django.contrib.auth import get_user_model
from accounts.models import Token
from celery import shared_task
@shared_task(bind=True)
def send_login_email_task(self, email):
    try:
        uid = str(uuid.uuid4())
        Token.objects.create(email=email, uid=uid)
        current_site = 'localhost:8000'
        mail_subject = 'Activate your account.'
        message = render_to_string('accounts/login_activation_email.html', {
            'domain': current_site,
            'uid': uid
        })
        print('called')
        email = EmailMessage(mail_subject, message, to=[email])
        email.send()
    except Token.DoesNotExist:
        logging.warning(
            "Tried to send activation email to non-existing user '%s'", email)
    except smtplib.SMTPException as exc:
        raise self.retry(exc=exc)

test_tasks.py

from django.test import TestCase
from unittest.mock import patch
from django.contrib.auth import get_user_model
from celery.exceptions import Retry
from proj.celery import App
import smtplib
import uuid

import accounts.tasks
from accounts.models import Token
@patch('accounts.tasks.EmailMessage')
def test_send_login_email_task(self, mock_email_message):
    # call task
    token = Token.objects.get(email=self.email, uid=self.uid)
    print(token.email)
    accounts.tasks.send_login_email_task.apply_async((token.email,))
    self.assertEqual(mock_email_message.called, True)
    # patch EmailMessage
    print(mock_email_message.call_args)
    args, kwargs = mock_email_message.call_args
    subject = args[0]
    self.assertEqual(subject, 'Activate your account.')
    self.assertEqual(kwargs, {'to': ['ama@example.com']})

相关内容

  • 没有找到相关文章

最新更新