diff --git a/docs/changelog.rst b/docs/changelog.rst index e1c8a982..a7109ca3 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -9,6 +9,13 @@ Compatibility * Official Django 6.1 support. +Improvements +^^^^^^^^^^^^ + +* Warn when ``--reuse-db`` is used with an in-memory SQLite database, since + such a database only lives for the duration of the process and can't be + reused between test runs. + v4.14.0 (2026-08-10) -------------------- diff --git a/docs/database.rst b/docs/database.rst index fcdd219a..9241077a 100644 --- a/docs/database.rst +++ b/docs/database.rst @@ -94,6 +94,11 @@ instantly be re used. This will allow much faster startup time for tests. This can be especially useful when running a few tests, when there are a lot of database tables to set up. +Note that ``--reuse-db`` has no effect for an in-memory SQLite database (the +default for SQLite): such a database only exists while the process is running, +so there is nothing to reuse between runs. pytest-django emits a warning in +this case. + ``--reuse-db`` will not pick up schema changes between test runs. You must run the tests with ``--reuse-db --create-db`` to re-create the database according to the new schema. Running without ``--reuse-db`` is also possible, since the diff --git a/pytest_django/fixtures.py b/pytest_django/fixtures.py index 07af3153..2ac364a8 100644 --- a/pytest_django/fixtures.py +++ b/pytest_django/fixtures.py @@ -191,6 +191,24 @@ def django_db_setup( # noqa: PLR0917 **setup_databases_args, ) + if django_db_keepdb and not django_db_createdb: + from django.db import connections + + in_memory_aliases = sorted( + alias + for alias in aliases + if connections[alias].vendor == "sqlite" and connections[alias].is_in_memory_db() + ) + if in_memory_aliases: + request.node.warn( + pytest.PytestWarning( + "--reuse-db has no effect for the in-memory sqlite database(s) " + f"{', '.join(repr(alias) for alias in in_memory_aliases)}: an in-memory " + "database only exists for the duration of the process, so there " + "is nothing to reuse between test runs." + ) + ) + yield if not django_db_keepdb: diff --git a/tests/test_db_setup.py b/tests/test_db_setup.py index 3cb04dbf..b929c862 100644 --- a/tests/test_db_setup.py +++ b/tests/test_db_setup.py @@ -620,3 +620,46 @@ class Migration(migrations.Migration): assert result.ret == 0 result.stdout.fnmatch_lines(["*test_something_without_db PASSED*"]) result.stdout.no_fnmatch_line("*mark_migrations_run*") + + +class TestSqliteReuseDbInMemory: + db_settings: ClassVar = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": ":memory:", + } + } + + def test_reuse_db_warns_for_in_memory_database(self, django_pytester: DjangoPytester) -> None: + "--reuse-db can't reuse an in-memory database, so warn about it." + django_pytester.create_test_module( + """ + import pytest + + @pytest.mark.django_db + def test_inner(): + pass + """ + ) + + result = django_pytester.runpytest_subprocess("-v", "--reuse-db") + assert result.ret == 0 + result.stdout.fnmatch_lines( + ["*--reuse-db has no effect for the in-memory sqlite database*"] + ) + + def test_no_warning_without_reuse_db(self, django_pytester: DjangoPytester) -> None: + "Without --reuse-db the warning must not be emitted." + django_pytester.create_test_module( + """ + import pytest + + @pytest.mark.django_db + def test_inner(): + pass + """ + ) + + result = django_pytester.runpytest_subprocess("-v") + assert result.ret == 0 + result.stdout.no_fnmatch_line("*--reuse-db has no effect*")