.. _test-backend: Testing your app ================ Django's own test runner makes sure your :ref:`test cases don't send email `, by loading a dummy EmailBackend that accumulates messages in memory rather than sending them. That works just fine with Anymail. Anymail also includes its own "test" EmailBackend. This is intended primarily for Anymail's internal testing, but you may find it useful for some of your test cases, too: * Like Django's locmem EmailBackend, Anymail's test EmailBackend collects sent messages in :data:`django.core.mail.outbox`. Django clears the outbox automatically between test cases. See :ref:`email testing tools ` in the Django docs for more information. * Unlike the locmem backend, Anymail's test backend processes the messages as though they would be sent by a generic ESP. This means every sent EmailMessage will end up with an :attr:`~anymail.message.AnymailMessage.anymail_status` attribute after sending, and some common problems like malformed addresses may be detected. (But no ESP-specific checks are run.) * Anymail's test backend also adds an :attr:`anymail_test_params` attribute to each EmailMessage as it sends it. This is a dict of the actual params that would be used to send the message, including both Anymail-specific attributes from the EmailMessage and options that would come from Anymail settings defaults. Here's an example: .. code-block:: python from django.core import mail from django.test import TestCase from django.test.utils import override_settings @override_settings(EMAIL_BACKEND='anymail.backends.test.EmailBackend') class SignupTestCase(TestCase): # Assume our app has a signup view that accepts an email address... def test_sends_confirmation_email(self): self.client.post("/account/signup/", {"email": "user@example.com"}) # Test that one message was sent: self.assertEqual(len(mail.outbox), 1) # Verify attributes of the EmailMessage that was sent: self.assertEqual(mail.outbox[0].to, ["user@example.com"]) self.assertEqual(mail.outbox[0].tags, ["confirmation"]) # an Anymail custom attr # Or verify the Anymail params, including any merged settings defaults: self.assertTrue(mail.outbox[0].anymail_test_params["track_clicks"]) Note that :data:`django.core.mail.outbox` is an "outbox," not an attempt to represent end users' *inboxes*. When using Django's default locmem EmailBackend, each outbox item represents a single call to an SMTP server. With Anymail's test EmailBackend, each outbox item represents a single call to an ESP's send API. (Anymail does not try to simulate how an ESP might further process the message for that API call: Anymail can't render :ref:`esp-stored-templates`, and it keeps a :ref:`batch send` message as a single outbox item, representing the single ESP API call that will send multiple messages. You can check ``outbox[n].anymail_test_params['is_batch_send']`` to see if a message would fall under Anymail's batch send logic.)