Django

Code

Changeset 5173

Show
Ignore:
Timestamp:
05/08/07 06:19:34 (1 year ago)
Author:
russellm
Message:

Added redirection for email services during test conditions.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/test/testcases.py

    r5156 r5173  
    22from urlparse import urlparse 
    33from django.db import transaction 
    4 from django.core import management 
     4from django.core import management, mail 
    55from django.db.models import get_apps 
    66from django.test.client import Client 
     
    3434 
    3535class TestCase(unittest.TestCase):     
    36     def install_fixtures(self): 
    37         """If the Test Case class has a 'fixtures' member, clear the database and 
    38         install the named fixtures at the start of each test. 
     36    def _pre_setup(self): 
     37        """Perform any pre-test setup. This includes: 
    3938         
     39            * If the Test Case class has a 'fixtures' member, clearing the  
     40            database and installing the named fixtures at the start of each test. 
     41            * Clearing the mail test outbox. 
     42             
    4043        """ 
    4144        management.flush(verbosity=0, interactive=False) 
    4245        if hasattr(self, 'fixtures'): 
    4346            management.load_data(self.fixtures, verbosity=0) 
    44  
     47        mail.outbox = [] 
     48         
    4549    def run(self, result=None): 
    46         """Wrapper around default run method so that user-defined Test Cases  
    47         automatically call install_fixtures without having to include a call to  
    48         super(). 
     50        """Wrapper around default run method to perform common Django test set up. 
     51        This means that user-defined Test Cases aren't required to include a call  
     52        to super().setUp(). 
    4953         
    5054        """ 
    5155        self.client = Client() 
    52         self.install_fixtures() 
     56        self._pre_setup() 
    5357        super(TestCase, self).run(result) 
    5458 
  • django/trunk/django/test/utils.py

    r4541 r5173  
    22from django.conf import settings 
    33from django.db import connection, transaction, backend 
    4 from django.core import management 
     4from django.core import management, mail 
    55from django.dispatch import dispatcher 
    66from django.test import signals 
     
    1919    return self.nodelist.render(context) 
    2020     
     21class TestSMTPConnection(object): 
     22    """A substitute SMTP connection for use during test sessions. 
     23    The test connection stores email messages in a dummy outbox, 
     24    rather than sending them out on the wire. 
     25     
     26    """ 
     27    def __init__(*args, **kwargs): 
     28        pass 
     29    def open(self): 
     30        "Mock the SMTPConnection open() interface" 
     31        pass 
     32    def close(self): 
     33        "Mock the SMTPConnection close() interface" 
     34        pass 
     35    def send_messages(self, messages): 
     36        "Redirect messages to the dummy outbox" 
     37        mail.outbox.extend(messages) 
     38 
    2139def setup_test_environment(): 
    2240    """Perform any global pre-test setup. This involves: 
    2341         
    2442        - Installing the instrumented test renderer 
     43        - Diverting the email sending functions to a test buffer 
    2544         
    2645    """ 
     
    2847    Template.render = instrumented_test_render 
    2948     
     49    mail.original_SMTPConnection = mail.SMTPConnection 
     50    mail.SMTPConnection = TestSMTPConnection 
     51 
     52    mail.outbox = [] 
     53     
    3054def teardown_test_environment(): 
    3155    """Perform any global post-test teardown. This involves: 
    3256 
    3357        - Restoring the original test renderer 
     58        - Restoring the email sending functions 
    3459         
    3560    """ 
    3661    Template.render = Template.original_render 
    3762    del Template.original_render 
     63     
     64    mail.SMTPConnection = mail.original_SMTPConnection 
     65    del mail.original_SMTPConnection 
     66     
     67    del mail.outbox 
    3868     
    3969def _set_autocommit(connection): 
  • django/trunk/docs/testing.txt

    r5169 r5173  
    178178* `Test Client`_ 
    179179* `TestCase`_ 
     180* `Email services`_ 
    180181 
    181182Test Client 
     
    258259 
    259260``login(**credentials)`` 
    260     ** New in Django development version ** 
     261    **New in Django development version** 
    261262 
    262263    On a production site, it is likely that some views will be protected from 
     
    290291~~~~~~~~~~~~~~~~~ 
    291292 
    292 The ``get()``, ``post()`` and ``login()`` methods all return a Response 
    293 object. This Response object has the following properties that can be used 
    294 for testing purposes: 
     293The ``get()`` and ``post()`` methods both return a Response object. This 
     294Response object has the following properties that can be used for testing 
     295purposes: 
    295296 
    296297    ===============  ========================================================== 
     
    397398Default Test Client 
    398399~~~~~~~~~~~~~~~~~~~ 
    399 ** New in Django development version ** 
     400**New in Django development version** 
    400401 
    401402Every test case in a ``django.test.TestCase`` instance has access to an 
     
    454455another test, or the order of test execution. 
    455456 
     457Emptying the test outbox 
     458~~~~~~~~~~~~~~~~~~~~~~~~ 
     459**New in Django development version** 
     460 
     461At the start of each test case, in addition to installing fixtures, 
     462Django clears the contents of the test email outbox. 
     463 
     464For more detail on email services during tests, see `Email services`_. 
     465 
    456466Assertions 
    457467~~~~~~~~~~ 
    458 ** New in Django development version ** 
     468**New in Django development version** 
    459469 
    460470Normal Python unit tests have a wide range of assertions, such as 
     
    492502    response. 
    493503 
     504Email services 
     505-------------- 
     506**New in Django development version** 
     507 
     508If your view makes use of the `Django email services`_, you don't really 
     509want email to be sent every time you run a test using that view. 
     510 
     511When the Django test framework is initialized, it transparently replaces the 
     512normal `SMTPConnection`_ class with a dummy implementation that redirects all 
     513email to a dummy outbox. This outbox, stored as ``django.core.mail.outbox``, 
     514is a simple list of all `EmailMessage`_ instances that have been sent. 
     515For example, during test conditions, it would be possible to run the following 
     516code:: 
     517 
     518    from django.core import mail 
     519 
     520    # Send message 
     521    mail.send_mail('Subject here', 'Here is the message.', 'from@example.com', 
     522        ['to@example.com'], fail_silently=False) 
     523 
     524    # One message has been sent 
     525    self.assertEqual(len(mail.outbox), 1) 
     526    # Subject of first message is correct 
     527    self.assertEqual(mail.outbox[0].subject, 'Subject here') 
     528 
     529The ``mail.outbox`` object does not exist under normal execution conditions. 
     530The outbox is created during test setup, along with the dummy `SMTPConnection`_. 
     531When the test framework is torn down, the standard `SMTPConnection`_ class 
     532is restored, and the test outbox is destroyed. 
     533 
     534As noted `previously`_, the test outbox is emptied at the start of every 
     535test in a Django TestCase. To empty the outbox manually, assign the empty list 
     536to mail.outbox:: 
     537 
     538    from django.core import mail 
     539 
     540    # Empty the test outbox 
     541    mail.outbox = [] 
     542 
     543.. _`Django email services`: ../email/ 
     544.. _`SMTPConnection`: ../email/#the-emailmessage-and-smtpconnection-classes 
     545.. _`EmailMessage`: ../email/#the-emailmessage-and-smtpconnection-classes 
     546.. _`previously`: #emptying-the-test-outbox 
    494547 
    495548Running tests 
     
    611664``setup_test_environment()`` 
    612665    Performs any global pre-test setup, such as the installing the 
    613     instrumentation of the template rendering system. 
     666    instrumentation of the template rendering system and setting up 
     667    the dummy SMTPConnection. 
    614668 
    615669``teardown_test_environment()`` 
    616670    Performs any global post-test teardown, such as removing the instrumentation 
    617     of the template rendering system
     671    of the template rendering system and restoring normal email services
    618672 
    619673``create_test_db(verbosity=1, autoclobber=False)`` 
  • django/trunk/tests/modeltests/test_client/models.py

    r5156 r5173  
    2121""" 
    2222from django.test import Client, TestCase 
     23from django.core import mail 
    2324 
    2425class ClientTest(TestCase): 
     
    233234        except KeyError: 
    234235            pass 
     236     
     237    def test_mail_sending(self): 
     238        "Test that mail is redirected to a dummy outbox during test setup" 
     239         
     240        response = self.client.get('/test_client/mail_sending_view/') 
     241        self.assertEqual(response.status_code, 200) 
     242         
     243        self.assertEqual(len(mail.outbox), 1) 
     244        self.assertEqual(mail.outbox[0].subject, 'Test message') 
     245        self.assertEqual(mail.outbox[0].body, 'This is a test email') 
     246        self.assertEqual(mail.outbox[0].from_email, 'from@example.com')  
     247        self.assertEqual(mail.outbox[0].to[0], 'first@example.com') 
     248        self.assertEqual(mail.outbox[0].to[1], 'second@example.com') 
     249 
     250    def test_mass_mail_sending(self): 
     251        "Test that mass mail is redirected to a dummy outbox during test setup" 
     252         
     253        response = self.client.get('/test_client/mass_mail_sending_view/') 
     254        self.assertEqual(response.status_code, 200) 
     255         
     256        self.assertEqual(len(mail.outbox), 2) 
     257        self.assertEqual(mail.outbox[0].subject, 'First Test message') 
     258        self.assertEqual(mail.outbox[0].body, 'This is the first test email') 
     259        self.assertEqual(mail.outbox[0].from_email, 'from@example.com')  
     260        self.assertEqual(mail.outbox[0].to[0], 'first@example.com') 
     261        self.assertEqual(mail.outbox[0].to[1], 'second@example.com') 
     262 
     263        self.assertEqual(mail.outbox[1].subject, 'Second Test message') 
     264        self.assertEqual(mail.outbox[1].body, 'This is the second test email') 
     265        self.assertEqual(mail.outbox[1].from_email, 'from@example.com')  
     266        self.assertEqual(mail.outbox[1].to[0], 'second@example.com') 
     267        self.assertEqual(mail.outbox[1].to[1], 'third@example.com') 
     268         
  • django/trunk/tests/modeltests/test_client/urls.py

    r5156 r5173  
    1212    (r'^login_protected_view/$', views.login_protected_view), 
    1313    (r'^session_view/$', views.session_view), 
    14     (r'^broken_view/$', views.broken_view) 
     14    (r'^broken_view/$', views.broken_view), 
     15    (r'^mail_sending_view/$', views.mail_sending_view), 
     16    (r'^mass_mail_sending_view/$', views.mass_mail_sending_view) 
    1517) 
  • django/trunk/tests/modeltests/test_client/views.py

    r5156 r5173  
    11from xml.dom.minidom import parseString 
     2from django.core.mail import EmailMessage, SMTPConnection 
    23from django.template import Context, Template 
    34from django.http import HttpResponse, HttpResponseRedirect 
     
    125126    """A view which just raises an exception, simulating a broken view.""" 
    126127    raise KeyError("Oops! Looks like you wrote some bad code.") 
     128 
     129def mail_sending_view(request): 
     130    EmailMessage( 
     131        "Test message",  
     132        "This is a test email",  
     133        "from@example.com",  
     134        ['first@example.com', 'second@example.com']).send() 
     135    return HttpResponse("Mail sent") 
     136 
     137def mass_mail_sending_view(request): 
     138    m1 = EmailMessage( 
     139        'First Test message',  
     140        'This is the first test email',  
     141        'from@example.com',  
     142        ['first@example.com', 'second@example.com']) 
     143    m2 = EmailMessage( 
     144        'Second Test message',  
     145        'This is the second test email',  
     146        'from@example.com',  
     147        ['second@example.com', 'third@example.com']) 
     148     
     149    c = SMTPConnection() 
     150    c.send_messages([m1,m2]) 
     151     
     152    return HttpResponse("Mail sent")