Ticket #4788: skipped_test_deco_r8127.diff

File skipped_test_deco_r8127.diff, 11.0 KB (added by devin, 16 years ago)

skip test decorators. changes to auth tests. and decorator tests and documentation.

  • django/test/simple.py

     
    1 import unittest
     1import sys, time, traceback, unittest
    22from django.conf import settings
    33from django.db.models import get_app, get_apps
    44from django.test import _doctest as doctest
     
    140140
    141141    old_name = settings.DATABASE_NAME
    142142    create_test_db(verbosity, autoclobber=not interactive)
    143     result = unittest.TextTestRunner(verbosity=verbosity).run(suite)
     143    result = SkipTestRunner(verbosity=verbosity).run(suite)
    144144    destroy_test_db(old_name, verbosity)
    145145   
    146146    teardown_test_environment()
    147147   
    148148    return len(result.failures) + len(result.errors)
     149
     150class SkipTestRunner:
     151    """
     152    A test runner class that adds a Skipped category in the output layer.
     153   
     154    Modeled after unittest.TextTestRunner.
     155
     156    Similarly to unittest.TextTestRunner, prints summary of the results at the end.
     157    (Including a count of skipped tests.)
     158    """
     159
     160    def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1):
     161        self.stream = unittest._WritelnDecorator(stream)
     162        self.descriptions = descriptions
     163        self.verbosity = verbosity
     164        self.result = _SkipTestResult(self.stream, descriptions, verbosity)
     165
     166    def run(self, test):
     167        "Run the given test case or test suite."
     168        startTime = time.time()
     169        test.run(self.result)
     170        stopTime = time.time()
     171        timeTaken = stopTime - startTime
     172       
     173        self.result.printErrors()
     174        self.stream.writeln(self.result.separator2)
     175        run = self.result.testsRun
     176        self.stream.writeln('Ran %d test%s in %.3fs' %
     177                (run, run != 1 and 's' or '', timeTaken))
     178        self.stream.writeln()
     179        if not self.result.wasSuccessful():
     180            self.stream.write('FAILED (')
     181            failed, errored, skipped = map(len, (self.result.failures, self.result.errors, self.result.skipped))
     182            if failed:
     183                self.stream.write('failures=%d' % failed)
     184            if errored:
     185                if failed: self.stream.write(', ')
     186                self.stream.write('errors=%d' % errored)
     187            if skipped:
     188                if errored or failed: self.stream.write(', ')
     189                self.stream.write('skipped=%d' % skipped)
     190            self.stream.writeln(')')
     191        else:
     192            self.stream.writeln('OK')
     193        return self.result
     194
     195class _SkipTestResult(unittest._TextTestResult):
     196    """
     197    A test result class that adds a Skipped category in the output layer.
     198   
     199    Modeled after unittest._TextTestResult.
     200   
     201    Similarly to unittest._TextTestResult, prints out the names of tests as they are
     202    run and errors as they occur.
     203    """
     204
     205    def __init__(self, stream, descriptions, verbosity):
     206        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
     207        self.skipped = []
     208
     209    def addError(self, test, err):
     210        # Determine if this is a skipped test
     211        tracebacks = traceback.extract_tb(err[2])
     212        if tracebacks[-1][-1].startswith('raise SkippedTest'):
     213            self.skipped.append((test, self._exc_info_to_string(err, test)))
     214            if self.showAll:
     215                self.stream.writeln('SKIPPED')
     216            elif self.dots:
     217                self.stream.write('S')
     218                self.stream.flush()
     219        else:
     220            unittest.TestResult.addError(self, test, err)
     221            if self.showAll:
     222                self.stream.writeln('ERROR')
     223            elif self.dots:
     224                self.stream.write('E')
     225                self.stream.flush()
     226
     227    def printErrors(self):
     228        if self.dots or self.showAll:
     229            self.stream.writeln()
     230        self.printErrorList('SKIPPED', self.skipped)
     231        self.printErrorList('ERROR', self.errors)
     232        self.printErrorList('FAIL', self.failures)
  • django/test/__init__.py

     
    44
    55from django.test.client import Client
    66from django.test.testcases import TestCase
     7
     8class SkippedTest(Exception):
     9   
     10    def __init__(self, reason):
     11        self.reason = reason
     12       
     13    def __str__(self):
     14        return self.reason
  • django/test/decorators.py

     
     1from django.core import urlresolvers
     2from django.test import SkippedTest
     3
     4def views_required(required_views=[]):
     5    def urls_found():
     6        try:
     7            for view in required_views:
     8                urlresolvers.reverse(view)
     9            return True
     10        except urlresolvers.NoReverseMatch:
     11            return False
     12    reason = 'Required view%s for this test not found: %s' % \
     13            (len(required_views) > 1 and 's' or '', ', '.join(required_views))
     14    return conditional_skip(urls_found, reason=reason)
     15
     16def modules_required(required_modules=[]):
     17    def modules_found():
     18        try:
     19            for module in required_modules:
     20                __import__(module)
     21            return True
     22        except ImportError:
     23            return False
     24    reason = 'Required module%s for this test not found: %s' % \
     25            (len(required_modules) > 1 and 's' or '', ', '.join(required_modules))
     26    return conditional_skip(modules_found, reason=reason)
     27
     28def skip_specific_database(database_engine):
     29    def database_check():
     30        from django.conf import settings
     31        return database_engine == settings.DATABASE_ENGINE
     32    reason = 'Test not run for database engine %s.' % database_engine
     33    return conditional_skip(database_check, reason=reason)
     34
     35def conditional_skip(required_condition, reason=''):
     36    if required_condition():
     37        return lambda x: x
     38    else:
     39        return skip_test(reason)
     40
     41def skip_test(reason=''):
     42    def _skip(x):
     43        raise SkippedTest(reason=reason)
     44    return lambda x: _skip
     45 No newline at end of file
  • django/contrib/auth/tests/basic.py

     
    5656"""
    5757
    5858from django.test import TestCase
     59from django.test.decorators import views_required
    5960from django.core import mail
    6061
    6162class PasswordResetTest(TestCase):
    6263    fixtures = ['authtestdata.json']
    63     urls = 'django.contrib.auth.urls'
    6464   
    6565    def test_email_not_found(self):
    6666        "Error is raised if the provided email address isn't currently registered"
     
    6969        response = self.client.post('/password_reset/', {'email': 'not_a_real_email@email.com'})
    7070        self.assertContains(response, "That e-mail address doesn't have an associated user account")
    7171        self.assertEquals(len(mail.outbox), 0)
     72    test_email_not_found = views_required(required_views=['django.contrib.auth.views.password_reset'])(test_email_not_found)
    7273   
    7374    def test_email_found(self):
    7475        "Email is sent if a valid email address is provided for password reset"
    7576        response = self.client.post('/password_reset/', {'email': 'staffmember@example.com'})
    7677        self.assertEquals(response.status_code, 302)
    7778        self.assertEquals(len(mail.outbox), 1)
     79    test_email_found = views_required(required_views=['django.contrib.auth.views.password_reset'])(test_email_found)
     80
  • tests/regressiontests/test_decorators/tests.py

     
     1r"""
     2>>> from django.test import SkippedTest
     3>>> from django.test.decorators import *
     4
     5>>> skip_test()(None)(None)
     6Traceback (most recent call last):
     7    ...
     8SkippedTest
     9
     10>>> skip_test(reason='testing')(None)(None)
     11Traceback (most recent call last):
     12    ...
     13SkippedTest: testing
     14
     15>>> conditional_skip(lambda: False)(None)(None)
     16Traceback (most recent call last):
     17    ...
     18SkippedTest
     19
     20>>> conditional_skip(lambda: True)(lambda: True)()
     21True
     22
     23"""
     24 No newline at end of file
  • docs/testing.txt

     
    830830This test case will use the contents of ``myapp.test_urls`` as the
    831831URLconf for the duration of the test case.
    832832
     833Skipping tests bound to fail
     834~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     835
     836**New in Django development version**
     837
     838Occasionally it's helpful to specify tests that are skipped under certain
     839circumstances. To accomplish this, the Django test framework offers decorators
     840that you can apply to your test methods for them to be conditionally skipped.
     841
     842You can supply your own condition function as follows::
     843
     844    from django.tests.decorators import *
     845   
     846    class TestUnderCondition(TestCase):
     847   
     848        def _my_condition():
     849            # Condition returning True if test should be run and False if it
     850            # should be skipped.
     851
     852        @conditional_skip(_my_condition, reason='This test should be skipped sometimes')
     853        def testOnlyOnTuesday(self):
     854            # Test to run if _my_condition evaluates to True
     855
     856In addition, the Django test framework supplies a handful of skip conditions that
     857handle commonly used conditions for skipping tests.
     858
     859``views_required(required_views=[])``
     860    Does a ``urlresolver.Reverse`` on the required views supplied. Runs test only if
     861    all views in ``required_views`` are in use.
     862
     863``modules_required(required_modules=[])``
     864    Runs tests only if all modules in ``required_modules`` can be imported.
     865
     866``skip_specific_database(database_engine)``
     867    Skips test if ``settings.DATABASE_ENGINE`` is equal to database_engine.
     868
     869If a test is skipped, it is added to a skipped category in the test runner and
     870the test results are reported as such::
     871
     872    ======================================================================
     873    SKIPPED: test_email_found (django.contrib.auth.tests.basic.PasswordResetTest)
     874    ----------------------------------------------------------------------
     875    Traceback (most recent call last):
     876      File "/Users/dnaquin/Dropbox/Sandbox/django/django/test/decorators.py", line 43, in _skip
     877        raise SkippedTest(reason=reason)
     878    SkippedTest: Required view for this test not found: django.contrib.auth.views.password_reset
     879
     880    ----------------------------------------------------------------------
     881    Ran 408 tests in 339.663s
     882
     883    FAILED (failures=1, skipped=2)
     884   
     885
    833886Emptying the test outbox
    834887~~~~~~~~~~~~~~~~~~~~~~~~
    835888
Back to Top