diff --git a/.gitignore b/.gitignore
index 206b38da04..238fb3a200 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
*.egg-info
*.pot
*.py[co]
+.tox/
__pycache__
MANIFEST
dist/
diff --git a/docs/internals/contributing/writing-code/coding-style.txt b/docs/internals/contributing/writing-code/coding-style.txt
index 46b12a11ed..137ab3e67f 100644
--- a/docs/internals/contributing/writing-code/coding-style.txt
+++ b/docs/internals/contributing/writing-code/coding-style.txt
@@ -4,6 +4,8 @@ Coding style
Please follow these coding standards when writing code for inclusion in Django.
+.. _coding-style-python:
+
Python style
============
@@ -51,6 +53,8 @@ Python style
(``six.assertRaisesRegex()`` as long as we support Python 2) only if you need
to use regular expression matching.
+.. _coding-style-imports:
+
Imports
=======
diff --git a/docs/internals/contributing/writing-code/javascript.txt b/docs/internals/contributing/writing-code/javascript.txt
index 8b8534e384..25a46695c3 100644
--- a/docs/internals/contributing/writing-code/javascript.txt
+++ b/docs/internals/contributing/writing-code/javascript.txt
@@ -60,6 +60,8 @@ Closure Compiler library requires `Java`_ 7 or higher.
Please don't forget to run ``compress.py`` and include the ``diff`` of the
minified scripts when submitting patches for Django's JavaScript.
+.. _javascript-tests:
+
JavaScript tests
================
diff --git a/docs/internals/contributing/writing-code/unit-tests.txt b/docs/internals/contributing/writing-code/unit-tests.txt
index f92174a9a9..188a71d5e6 100644
--- a/docs/internals/contributing/writing-code/unit-tests.txt
+++ b/docs/internals/contributing/writing-code/unit-tests.txt
@@ -45,6 +45,73 @@ See :ref:`installing-development-version`.
Having problems? See :ref:`troubleshooting-unit-tests` for some common issues.
+Running tests using ``tox``
+---------------------------
+
+`Tox `_ is a tool for running tests in different
+virtual environments. Django includes a basic ``tox.ini`` that automates some
+checks that our build server performs on pull requests. To run the unit tests
+and other checks (such as :ref:`import sorting `, the
+:ref:`documentation spelling checker `, and
+:ref:`code formatting `), install and run the ``tox``
+command from any place in the Django source tree::
+
+ $ pip install tox
+ $ tox
+
+By default, ``tox`` runs the test suite with the bundled test settings file for
+SQLite, ``flake8``, ``isort``, and the documentation spelling checker. In
+addition to the system dependencies noted elsewhere in this documentation,
+the commands ``python2`` and ``python3`` must be on your path and linked to
+the appropriate versions of Python. A list of default environments can be seen
+as follows::
+
+ $ tox -l
+ py3
+ flake8
+ docs
+ isort
+
+Testing other Python versions and database backends
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In addition to the default environments, ``tox`` supports running unit tests
+for other versions of Python and other database backends. Since Django's test
+suite doesn't bundle a settings file for database backends other than SQLite,
+however, you must :ref:`create and provide your own test settings
+`. For example, to run the tests on Python 3.5
+using PostgreSQL::
+
+ $ tox -e py35-postgres -- --settings=my_postgres_settings
+
+This command sets up a Python 3.5 virtual environment, installs Django's
+test suite dependencies (including those for PostgreSQL), and calls
+``runtests.py`` with the supplied arguments (in this case,
+``--settings=my_postgres_settings``).
+
+The remainder of this documentation shows commands for running tests without
+``tox``, however, any option passed to ``runtests.py`` can also be passed to
+``tox`` by prefixing the argument list with ``--``, as above.
+
+Tox also respects the ``DJANGO_SETTINGS_MODULE`` environment variable, if set.
+For example, the following is equivalent to the command above::
+
+ $ DJANGO_SETTINGS_MODULE=my_postgres_settings tox -e py35-postgres
+
+Running the JavaScript tests
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Django includes a set of :ref:`JavaScript unit tests ` for
+functions in certain contrib apps. The JavaScript tests aren't run by default
+using ``tox`` because they require `Node.js` to be installed and aren't
+necessary for the majority of patches. To run the JavaScript tests using
+``tox``::
+
+ $ tox -e javascript
+
+This command runs ``npm install`` to ensure test requirements are up to
+date and then runs ``npm test``.
+
.. _running-unit-tests-settings:
Using another ``settings`` module
diff --git a/docs/spelling_wordlist b/docs/spelling_wordlist
index 557d139a3e..5a935d30e1 100644
--- a/docs/spelling_wordlist
+++ b/docs/spelling_wordlist
@@ -841,6 +841,7 @@ Tomek
toolbar
toolkits
toolset
+Tox
trac
tracebacks
transactional
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000000..cdf47bb00c
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,69 @@
+# Tox (http://tox.testrun.org/) is a tool for running tests in multiple
+# virtualenvs. This configuration file helps to run the test suite on all
+# supported Python versions. To use it, "pip install tox" and then run "tox"
+# from this directory.
+
+[tox]
+skipsdist = true
+envlist =
+ py3
+ flake8
+ docs
+ isort
+
+# Add environments to use default python2 and python3 installations
+[testenv:py2]
+basepython = python2
+
+[testenv:py3]
+basepython = python3
+
+[testenv]
+usedevelop = true
+passenv = DJANGO_SETTINGS_MODULE
+deps =
+ py{2,27}: -rtests/requirements/py2.txt
+ py{3,34,35}: -rtests/requirements/py3.txt
+ postgres: -rtests/requirements/postgres.txt
+ mysql: -rtests/requirements/mysql.txt
+ oracle: -rtests/requirements/oracle.txt
+changedir = tests
+commands =
+ {envpython} runtests.py {posargs}
+
+[testenv:flake8]
+basepython = python3
+usedevelop = false
+deps = flake8
+changedir = {toxinidir}
+commands = flake8 .
+
+[testenv:docs]
+# On OS X, as of pyenchant 1.6.6, the docs build only works under Python 2.
+basepython = python2
+usedevelop = false
+whitelist_externals =
+ make
+deps =
+ Sphinx
+ pyenchant
+ sphinxcontrib-spelling
+changedir = docs
+commands =
+ make spelling
+
+[testenv:isort]
+basepython = python3
+usedevelop = false
+deps = isort
+changedir = {toxinidir}
+commands = isort --recursive --check-only --diff django tests scripts
+
+[testenv:javascript]
+usedevelop = false
+deps =
+changedir = {toxinidir}
+whitelist_externals = npm
+commands =
+ npm install
+ npm test