diff --git a/django/test/__init__.py b/django/test/__init__.py index 32608a94f2..b65601b12d 100644 --- a/django/test/__init__.py +++ b/django/test/__init__.py @@ -16,3 +16,12 @@ __all__ = [ 'skipUnlessDBFeature', 'modify_settings', 'override_settings', 'override_system_checks' ] + +# To simplify Django's test suite; not meant as a public API +try: + from unittest import mock # NOQA +except ImportError: + try: + import mock # NOQA + except ImportError: + pass diff --git a/docs/internals/contributing/writing-code/unit-tests.txt b/docs/internals/contributing/writing-code/unit-tests.txt index 2497c5e65a..6067e9635d 100644 --- a/docs/internals/contributing/writing-code/unit-tests.txt +++ b/docs/internals/contributing/writing-code/unit-tests.txt @@ -24,6 +24,11 @@ Running the unit tests Quickstart ~~~~~~~~~~ +If you are on Python < 3.3, you'll first need to install a backport of the +``unittest.mock`` module that's available in Python 3.3+. See +:ref:`running-unit-tests-dependencies` for details on installing `mock`_ and +the other optional test dependencies. + Running the tests requires a Django settings module that defines the databases to use. To make it easy to get started, Django provides and uses a sample settings module that uses the SQLite database. To run the tests: @@ -166,6 +171,7 @@ dependencies: * pytz_ * setuptools_ * memcached_, plus a :ref:`supported Python binding ` +* mock_ (for Python < 3.3) * gettext_ (:ref:`gettext_on_windows`) * selenium_ * sqlparse_ @@ -176,7 +182,7 @@ like so: .. code-block:: bash - $ pip install -r tests/requirements/py2.txt # Python 3: py3.txt + $ pip install -r tests/requirements/py3.txt # Python 2: py2.txt You can also install the database adapter(s) of your choice using ``oracle.txt``, ``mysql.txt``, or ``postgres.txt``. @@ -198,6 +204,7 @@ associated tests will be skipped. .. _pytz: https://pypi.python.org/pypi/pytz/ .. _setuptools: https://pypi.python.org/pypi/setuptools/ .. _memcached: http://memcached.org/ +.. _mock: https://pypi.python.org/pypi/mock .. _gettext: http://www.gnu.org/software/gettext/manual/gettext.html .. _selenium: https://pypi.python.org/pypi/selenium .. _sqlparse: https://pypi.python.org/pypi/sqlparse diff --git a/tests/README.rst b/tests/README.rst index 1a12cad3fa..73bce435e2 100644 --- a/tests/README.rst +++ b/tests/README.rst @@ -1,5 +1,7 @@ To run the test suite:: + $ cd tests + $ pip install -r requirements/py3.txt # or py2.txt $ PYTHONPATH=..:$PYTHONPATH ./runtests.py For more information about the test suite, see diff --git a/tests/requirements/base.txt b/tests/requirements/base.txt index c3f77234fd..c38e8695aa 100644 --- a/tests/requirements/base.txt +++ b/tests/requirements/base.txt @@ -1,5 +1,7 @@ bcrypt docutils +# move to py2.txt when dropping Python 3.2 +mock numpy Pillow PyYAML diff --git a/tests/runtests.py b/tests/runtests.py index a336b7f6d2..1ae7c93150 100755 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -374,6 +374,16 @@ if __name__ == "__main__": help='Run the Selenium tests as well (if Selenium is installed)') options = parser.parse_args() + # mock is a required dependency + try: + from django.test import mock # NOQA + except ImportError: + print( + "Please install test dependencies first: \n" + "$ pip install -r requirements/py%s.txt" % sys.version_info.major + ) + sys.exit(1) + # Allow including a trailing slash on app_labels for tab completion convenience options.modules = [os.path.normpath(labels) for labels in options.modules] diff --git a/tests/test_runner/tests.py b/tests/test_runner/tests.py index d38d27f30c..a8ce8d947c 100644 --- a/tests/test_runner/tests.py +++ b/tests/test_runner/tests.py @@ -10,7 +10,7 @@ from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.core.management import call_command from django.db.backends.dummy.base import DatabaseCreation -from django.test import TestCase, TransactionTestCase, skipUnlessDBFeature +from django.test import TestCase, TransactionTestCase, mock, skipUnlessDBFeature from django.test.runner import DiscoverRunner, dependency_ordered from django.test.testcases import connections_support_transactions from django.utils import six @@ -129,13 +129,10 @@ class DependencyOrderingTests(unittest.TestCase): class MockTestRunner(object): - invoked = False - def __init__(self, *args, **kwargs): pass - def run_tests(self, test_labels, extra_tests=None, **kwargs): - MockTestRunner.invoked = True +MockTestRunner.run_tests = mock.Mock(return_value=[]) class ManageCommandTests(unittest.TestCase): @@ -143,8 +140,7 @@ class ManageCommandTests(unittest.TestCase): def test_custom_test_runner(self): call_command('test', 'sites', testrunner='test_runner.tests.MockTestRunner') - self.assertTrue(MockTestRunner.invoked, - "The custom test runner has not been invoked") + MockTestRunner.run_tests.assert_called_with(('sites',)) def test_bad_test_runner(self): with self.assertRaises(AttributeError):