Removed django.test.simple and django.test._doctest per deprecation timeline.

refs #17365, #17366, #18727.
This commit is contained in:
Tim Graham 2014-03-21 13:30:40 -04:00
parent b71f183d2e
commit bf5430a20b
9 changed files with 3 additions and 3162 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,251 +0,0 @@
"""
This module is pending deprecation as of Django 1.6 and will be removed in
version 1.8.
"""
from importlib import import_module
import json
import re
import unittest as real_unittest
import warnings
from django.apps import apps
from django.test import _doctest as doctest
from django.test import runner
from django.test.utils import compare_xml, strip_quotes
# django.utils.unittest is deprecated, but so is django.test.simple,
# and the latter will be removed before the former.
from django.utils import unittest
from django.utils.deprecation import RemovedInDjango18Warning
from django.utils.module_loading import module_has_submodule
__all__ = ('DjangoTestSuiteRunner',)
warnings.warn(
"The django.test.simple module and DjangoTestSuiteRunner are deprecated; "
"use django.test.runner.DiscoverRunner instead.",
RemovedInDjango18Warning)
# The module name for tests outside models.py
TEST_MODULE = 'tests'
normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s)
normalize_decimals = lambda s: re.sub(r"Decimal\('(\d+(\.\d*)?)'\)",
lambda m: "Decimal(\"%s\")" % m.groups()[0], s)
class OutputChecker(doctest.OutputChecker):
def check_output(self, want, got, optionflags):
"""
The entry method for doctest output checking. Defers to a sequence of
child checkers
"""
checks = (self.check_output_default,
self.check_output_numeric,
self.check_output_xml,
self.check_output_json)
for check in checks:
if check(want, got, optionflags):
return True
return False
def check_output_default(self, want, got, optionflags):
"""
The default comparator provided by doctest - not perfect, but good for
most purposes
"""
return doctest.OutputChecker.check_output(self, want, got, optionflags)
def check_output_numeric(self, want, got, optionflags):
"""Doctest does an exact string comparison of output, which means that
some numerically equivalent values aren't equal. This check normalizes
* long integers (22L) so that they equal normal integers. (22)
* Decimals so that they are comparable, regardless of the change
made to __repr__ in Python 2.6.
"""
return doctest.OutputChecker.check_output(self,
normalize_decimals(normalize_long_ints(want)),
normalize_decimals(normalize_long_ints(got)),
optionflags)
def check_output_xml(self, want, got, optionsflags):
try:
return compare_xml(want, got)
except Exception:
return False
def check_output_json(self, want, got, optionsflags):
"""
Tries to compare want and got as if they were JSON-encoded data
"""
want, got = strip_quotes(want, got)
try:
want_json = json.loads(want)
got_json = json.loads(got)
except Exception:
return False
return want_json == got_json
class DocTestRunner(doctest.DocTestRunner):
def __init__(self, *args, **kwargs):
doctest.DocTestRunner.__init__(self, *args, **kwargs)
self.optionflags = doctest.ELLIPSIS
doctestOutputChecker = OutputChecker()
def get_tests(app_config):
try:
test_module = import_module('%s.%s' % (app_config.name, TEST_MODULE))
except ImportError:
# Couldn't import tests.py. Was it due to a missing file, or
# due to an import error in a tests.py that actually exists?
if not module_has_submodule(app_config.module, TEST_MODULE):
test_module = None
else:
# The module exists, so there must be an import error in the test
# module itself.
raise
return test_module
def make_doctest(module):
return doctest.DocTestSuite(module,
checker=doctestOutputChecker,
runner=DocTestRunner)
def build_suite(app_config):
"""
Create a complete Django test suite for the provided application module.
"""
suite = unittest.TestSuite()
# Load unit and doctests in the models.py module. If module has
# a suite() method, use it. Otherwise build the test suite ourselves.
models_module = app_config.models_module
if models_module:
if hasattr(models_module, 'suite'):
suite.addTest(models_module.suite())
else:
suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(
models_module))
try:
suite.addTest(make_doctest(models_module))
except ValueError:
# No doc tests in models.py
pass
# Check to see if a separate 'tests' module exists parallel to the
# models module
tests_module = get_tests(app_config)
if tests_module:
# Load unit and doctests in the tests.py module. If module has
# a suite() method, use it. Otherwise build the test suite ourselves.
if hasattr(tests_module, 'suite'):
suite.addTest(tests_module.suite())
else:
suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(
tests_module))
try:
suite.addTest(make_doctest(tests_module))
except ValueError:
# No doc tests in tests.py
pass
return suite
def build_test(label):
"""
Construct a test case with the specified label. Label should be of the
form app_label.TestClass or app_label.TestClass.test_method. Returns an
instantiated test or test suite corresponding to the label provided.
"""
parts = label.split('.')
if len(parts) < 2 or len(parts) > 3:
raise ValueError("Test label '%s' should be of the form app.TestCase "
"or app.TestCase.test_method" % label)
app_config = apps.get_app_config(parts[0])
models_module = app_config.models_module
tests_module = get_tests(app_config)
test_modules = []
if models_module:
test_modules.append(models_module)
if tests_module:
test_modules.append(tests_module)
TestClass = None
for module in test_modules:
TestClass = getattr(models_module, parts[1], None)
if TestClass is not None:
break
try:
if issubclass(TestClass, (unittest.TestCase, real_unittest.TestCase)):
if len(parts) == 2: # label is app.TestClass
try:
return unittest.TestLoader().loadTestsFromTestCase(
TestClass)
except TypeError:
raise ValueError(
"Test label '%s' does not refer to a test class"
% label)
else: # label is app.TestClass.test_method
return TestClass(parts[2])
except TypeError:
# TestClass isn't a TestClass - it must be a method or normal class
pass
#
# If there isn't a TestCase, look for a doctest that matches
#
tests = []
for module in test_modules:
try:
doctests = make_doctest(module)
# Now iterate over the suite, looking for doctests whose name
# matches the pattern that was given
for test in doctests:
if test._dt_test.name in (
'%s.%s' % (module.__name__, '.'.join(parts[1:])),
'%s.__test__.%s' % (
module.__name__, '.'.join(parts[1:]))):
tests.append(test)
except ValueError:
# No doctests found.
pass
# If no tests were found, then we were given a bad test label.
if not tests:
raise ValueError("Test label '%s' does not refer to a test" % label)
# Construct a suite out of the tests that matched.
return unittest.TestSuite(tests)
class DjangoTestSuiteRunner(runner.DiscoverRunner):
def build_suite(self, test_labels, extra_tests=None, **kwargs):
suite = unittest.TestSuite()
if test_labels:
for label in test_labels:
if '.' in label:
suite.addTest(build_test(label))
else:
app_config = apps.get_app_config(label)
suite.addTest(build_suite(app_config))
else:
for app_config in apps.get_app_configs():
suite.addTest(build_suite(app_config))
if extra_tests:
for test in extra_tests:
suite.addTest(test)
return runner.reorder_suite(suite, (unittest.TestCase,))

View File

@ -2067,11 +2067,6 @@ Default: ``'django.test.runner.DiscoverRunner'``
The name of the class to use for starting the test suite. See The name of the class to use for starting the test suite. See
:ref:`other-testing-frameworks`. :ref:`other-testing-frameworks`.
.. versionchanged:: 1.6
Previously the default ``TEST_RUNNER`` was
``django.test.simple.DjangoTestSuiteRunner``.
.. setting:: THOUSAND_SEPARATOR .. setting:: THOUSAND_SEPARATOR
THOUSAND_SEPARATOR THOUSAND_SEPARATOR

View File

@ -3,7 +3,7 @@ doc_files = docs extras AUTHORS INSTALL LICENSE README.rst
install-script = scripts/rpm-install.sh install-script = scripts/rpm-install.sh
[flake8] [flake8]
exclude=build,.git,./django/utils/dictconfig.py,./django/utils/unittest.py,./django/utils/lru_cache.py,./tests/comment_tests/*,./django/test/_doctest.py,./django/utils/six.py,./django/conf/app_template/*,./django/dispatch/weakref_backports.py exclude=build,.git,./django/utils/dictconfig.py,./django/utils/unittest.py,./django/utils/lru_cache.py,./django/utils/six.py,./django/conf/app_template/*,./django/dispatch/weakref_backports.py
ignore=E128,E501,W601 ignore=E128,E501,W601
[metadata] [metadata]

View File

@ -4,7 +4,6 @@ Tests for django test runner
from __future__ import unicode_literals from __future__ import unicode_literals
from optparse import make_option from optparse import make_option
import types
import unittest import unittest
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
@ -12,7 +11,7 @@ from django.core.management import call_command
from django import db from django import db
from django.test import runner, TestCase, TransactionTestCase, skipUnlessDBFeature from django.test import runner, TestCase, TransactionTestCase, skipUnlessDBFeature
from django.test.testcases import connections_support_transactions from django.test.testcases import connections_support_transactions
from django.test.utils import IgnoreAllDeprecationWarningsMixin, override_system_checks from django.test.utils import override_system_checks
from django.utils import six from django.utils import six
from admin_scripts.tests import AdminScriptTestCase from admin_scripts.tests import AdminScriptTestCase
@ -221,27 +220,6 @@ class Ticket17477RegressionTests(AdminScriptTestCase):
self.assertNoOutput(err) self.assertNoOutput(err)
class ModulesTestsPackages(IgnoreAllDeprecationWarningsMixin, unittest.TestCase):
def test_get_tests(self):
"Check that the get_tests helper function can find tests in a directory"
from django.apps import AppConfig
from django.test.simple import get_tests
app_config = AppConfig.create('test_runner.valid_app')
app_config.import_models({})
tests = get_tests(app_config)
self.assertIsInstance(tests, types.ModuleType)
def test_import_error(self):
"Test for #12658 - Tests with ImportError's shouldn't fail silently"
from django.apps import AppConfig
from django.test.simple import get_tests
app_config = AppConfig.create('test_runner_invalid_app')
app_config.import_models({})
with self.assertRaises(ImportError):
get_tests(app_config)
class Sqlite3InMemoryTestDbs(TestCase): class Sqlite3InMemoryTestDbs(TestCase):
available_apps = [] available_apps = []

View File

@ -1,37 +0,0 @@
import unittest
from django.apps import apps
from django.test.utils import IgnoreAllDeprecationWarningsMixin
def suite():
testSuite = unittest.TestSuite()
testSuite.addTest(SuiteOverrideTest('test_suite_override'))
return testSuite
class SuiteOverrideTest(IgnoreAllDeprecationWarningsMixin, unittest.TestCase):
def test_suite_override(self):
"""
Validate that you can define a custom suite when running tests with
``django.test.simple.DjangoTestSuiteRunner`` (which builds up a test
suite using ``build_suite``).
"""
from django.test.simple import build_suite
app_config = apps.get_app_config("test_suite_override")
suite = build_suite(app_config)
self.assertEqual(suite.countTestCases(), 1)
class SampleTests(unittest.TestCase):
"""These tests should not be discovered, due to the custom suite."""
def test_one(self):
pass
def test_two(self):
pass
def test_three(self):
pass

View File

@ -1,77 +0,0 @@
from django.utils import six
__test__ = {"API_TEST": r"""
# Some checks of the doctest output normalizer.
# Standard doctests do fairly
>>> import json
>>> from django.utils.xmlutils import SimplerXMLGenerator
>>> from django.utils.six import StringIO
>>> def produce_json():
... return json.dumps(['foo', {'bar': ('baz', None, 1.0, 2), 'whiz': 42}])
>>> def produce_xml():
... stream = StringIO()
... xml = SimplerXMLGenerator(stream, encoding='utf-8')
... xml.startDocument()
... xml.startElement("foo", {"aaa" : "1.0", "bbb": "2.0"})
... xml.startElement("bar", {"ccc" : "3.0"})
... xml.characters("Hello")
... xml.endElement("bar")
... xml.startElement("whiz", {})
... xml.characters("Goodbye")
... xml.endElement("whiz")
... xml.endElement("foo")
... xml.endDocument()
... return stream.getvalue()
>>> def produce_xml_fragment():
... stream = StringIO()
... xml = SimplerXMLGenerator(stream, encoding='utf-8')
... xml.startElement("foo", {"aaa": "1.0", "bbb": "2.0"})
... xml.characters("Hello")
... xml.endElement("foo")
... xml.startElement("bar", {"ccc": "3.0", "ddd": "4.0"})
... xml.endElement("bar")
... return stream.getvalue()
# JSON output is normalized for field order, so it doesn't matter
# which order json dictionary attributes are listed in output
>>> produce_json()
'["foo", {"bar": ["baz", null, 1.0, 2], "whiz": 42}]'
>>> produce_json()
'["foo", {"whiz": 42, "bar": ["baz", null, 1.0, 2]}]'
# XML output is normalized for attribute order, so it doesn't matter
# which order XML element attributes are listed in output
>>> produce_xml()
'<?xml version="1.0" encoding="UTF-8"?>\n<foo aaa="1.0" bbb="2.0"><bar ccc="3.0">Hello</bar><whiz>Goodbye</whiz></foo>'
>>> produce_xml()
'<?xml version="1.0" encoding="UTF-8"?>\n<foo bbb="2.0" aaa="1.0"><bar ccc="3.0">Hello</bar><whiz>Goodbye</whiz></foo>'
>>> produce_xml_fragment()
'<foo aaa="1.0" bbb="2.0">Hello</foo><bar ccc="3.0" ddd="4.0"></bar>'
>>> produce_xml_fragment()
'<foo bbb="2.0" aaa="1.0">Hello</foo><bar ddd="4.0" ccc="3.0"></bar>'
"""}
if six.PY2:
__test__["API_TEST"] += """
>>> def produce_long():
... return 42L
>>> def produce_int():
... return 42
# Long values are normalized and are comparable to normal integers ...
>>> produce_long()
42
# ... and vice versa
>>> produce_int()
42L
"""

View File

@ -11,8 +11,7 @@ from django.http import HttpResponse
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.test import SimpleTestCase, TestCase, skipIfDBFeature, skipUnlessDBFeature from django.test import SimpleTestCase, TestCase, skipIfDBFeature, skipUnlessDBFeature
from django.test.html import HTMLParseError, parse_html from django.test.html import HTMLParseError, parse_html
from django.test.utils import (CaptureQueriesContext, from django.test.utils import CaptureQueriesContext, override_settings
IgnoreAllDeprecationWarningsMixin, override_settings)
from django.utils import six from django.utils import six
from .models import Person from .models import Person
@ -623,15 +622,6 @@ class AssertFieldOutputTests(SimpleTestCase):
self.assertFieldOutput(MyCustomField, {}, {}, empty_value=None) self.assertFieldOutput(MyCustomField, {}, {}, empty_value=None)
class DoctestNormalizerTest(IgnoreAllDeprecationWarningsMixin, SimpleTestCase):
def test_normalizer(self):
from django.test.simple import make_doctest
suite = make_doctest("test_utils.doctest_output")
failures = unittest.TextTestRunner(stream=six.StringIO()).run(suite)
self.assertEqual(failures.failures, [])
# for OverrideSettingsTests # for OverrideSettingsTests
def fake_view(request): def fake_view(request):
pass pass