30

Seems like "manage.py test" creates test database every time I run the test. Is there a way to prevent creating test database each time I run test but just truncate data (flush)?

My tables are almost about 40 tables (even for single app, not the whole project), and makes me sick every time I run test.

Cœur
  • 37,241
  • 25
  • 195
  • 267
CIF
  • 1,754
  • 2
  • 18
  • 30

8 Answers8

38

From Django 1.8 on you could use the --keepdb flag, when calling the manage.py

New in Django 1.8: You can prevent the test databases from being destroyed by adding the --keepdb flag to the test command. This will preserve the test database between runs. If the database does not exist, it will first be created. Any migrations will also be applied in order to keep it up to date. (https://docs.djangoproject.com/en/1.8/topics/testing/overview/#the-test-database)

So your call could look as follows:

python manage.py test --keepdb

Or using the shorthand -k it could look like that:

python manage.py test -k
Kim
  • 1,361
  • 3
  • 18
  • 24
  • For modern Django (1.8 or higher) with default test kit - that's the easiest. – Sibirsky Apr 27 '16 at 05:22
  • 1
    Even with keepdb, django insists on running migrations every time – Matt May 08 '17 at 17:31
  • 1
    @Matt _If the test database does not exist, it will be created on the first run and then preserved for each subsequent run. Any unapplied migrations will also be applied to the test database before running the test suite._ [django-docs](https://docs.djangoproject.com/en/1.11/ref/django-admin/#cmdoption-test-keepdb) – Kim May 10 '17 at 15:05
  • 3
    @Matt But yes, the migrations will be applied every time you run the tests (see the [django-source](https://github.com/django/django/blob/master/django/db/backends/base/creation.py#L63L69) for reference). However, running the tests with a higher verbosity mode (`python manage.py test -k --verbosity 2`), you will see the migrations are only checked, but not reapplied if they have been applied before and were not changed in between test runs. – Kim May 10 '17 at 16:13
13

Depending on your needs you have a few choices:

Community
  • 1
  • 1
Tomasz Zieliński
  • 16,136
  • 7
  • 59
  • 83
2

You maybe can try with test runner

Example:

First, create test_runners.py

from django.test.runner import DiscoverRunner


class NoDbTestRunner(DiscoverRunner):

    def setup_databases(self, **kwargs):
        """ Override the database creation defined in parent class """
        pass

    def teardown_databases(self, old_config, **kwargs):
        """ Override the database teardown defined in parent class """
        pass

Then declare above runner in settings.py

TEST_RUNNER = 'api.tests.test_runners.NoDbTestRunner'
Tho
  • 23,158
  • 6
  • 60
  • 47
1

django-nose supports reusing the database:

https://github.com/django-nose/django-nose#enabling-database-reuse

However, make sure to read the comments:

The one new wrinkle is that, whenever your DB schema changes, you should leave the flag off the next time you run tests. This will cue the test runner to reinitialize the test database.

Also, REUSE_DB is not compatible with TransactionTestCases that leave junk in the DB, so be sure to make your TransactionTestCases hygienic (see below) if you want to use it.

benjaoming
  • 2,135
  • 1
  • 21
  • 29
1

The following solution will also reduce the db creation time if there are more number of south migrations. During unit testing, running syncdb instead of running all the south migrations will be much faster.

SOUTH_TESTS_MIGRATE = False # To disable migrations and use syncdb instead

venkat
  • 2,310
  • 1
  • 15
  • 15
0

I'm guessing this is not best practice, but something that I have done as a workaround is to create a few different test programs in the management/commands directory within the app.

https://docs.djangoproject.com/en/1.7/howto/custom-management-commands/

For example, I'm working on an app now that requires some advanced Postgres functionality (cannot use Sqlite) so instead of creating test functions as part of tests.py, I created test_process.py in myapp/management/commands/

Joe Fusaro
  • 847
  • 2
  • 11
  • 23
0

You may want to have pytest as test runner. Configuration example follows.

Sample pytest.ini file:

[pytest]
norecursedirs=
    *.egg
    .git
    .tox
    .env
    _sass
    build
    dist
    migrations
    fabfile
    .tox
python_files =
    test_*.py
    tests.py
DJANGO_SETTINGS_MODULE=settings.dev
addopts=
   --reuse-db
   --nomigrations
   --cov=your_app
   --ignore=.tox
   --ignore=fabfile
   --ignore=scripts
   --ignore=settings
   --ignore=tmp
   --cov-report=html
   --cov-report=term
   --cov-report=annotate

Sample runtests.py file:

#!/usr/bin/env python
import os
import sys

import pytest


def main():
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.dev")
    return pytest.main()


if __name__ == '__main__':
    sys.exit(main())

Sample requirements.txt file:

pytest==3.0.2
pytest-django==2.9.1
pytest-cov==2.2.1

Run the tests:

./runtests.py

Note, that effect is achieved through reuse-db and nomigrations directives.

Artur Barseghyan
  • 12,746
  • 4
  • 52
  • 44
0

Current versions of Django have a --keepdb argument you can pass to tests so the database doesn't get destroyed and rebuilt on each run.

https://docs.djangoproject.com/en/3.0/ref/django-admin/#cmdoption-test-keepdb

vjimw
  • 951
  • 1
  • 9
  • 18