Почему тестовые примеры Django проверяют реальную БД и выдают IntegrityError, а не просто выполняются в памяти?

Когда я запускаю свои тесты с пустой БД (реальная БД приложения), все проходит нормально. Но когда в БД есть данные, Django поднимает IntegrityError практически для каждого теста. Трассировка stact выглядит следующим образом (но для каждого теста):

======================================================================
ERROR: test_api_get_detail (core.projects.tests.test_project_api.ProjectConfidentialPrivateAPITests)
Getting confidential object via API (GET)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/ramonkcom/Desktop/management/management-backend/venv/lib/python3.10/site-packages/django/test/testcases.py", line 299, in _setup_and_call
    self._post_teardown()
  File "/Users/ramonkcom/Desktop/management/management-backend/venv/lib/python3.10/site-packages/django/test/testcases.py", line 1199, in _post_teardown
    self._fixture_teardown()
  File "/Users/ramonkcom/Desktop/management/management-backend/venv/lib/python3.10/site-packages/django/test/testcases.py", line 1461, in _fixture_teardown
    connections[db_name].check_constraints()
  File "/Users/ramonkcom/Desktop/management/management-backend/venv/lib/python3.10/site-packages/django/db/backends/sqlite3/base.py", line 383, in check_constraints
    raise IntegrityError(
django.db.utils.IntegrityError: The row in table 'custom_fields_customfield' with primary key '1' has an invalid foreign key: custom_fields_customfield.definition_id contains a value '1' that does not have a corresponding value in custom_fields_customfielddefinition.id.

Сначала я подумал, что это проблема с моими приспособлениями. Но они прекрасно работают для установки базовых данных приложения. Похоже, ключевой проблемой является БД: если в ней есть данные, тесты падают, если она пуста, тесты работают.

Самым странным является то, что выдаваемая ошибка не соответствует действительности, и под этим я подразумеваю: объект CustomFieldDefinition с pk=1 существует в БД. В любом случае, это не должно иметь значения, поскольку я ожидаю, что Django будет создавать in-memory DB для каждого теста. Это просто дополнительная информация для загадки.

Что может заставить Django проверять реальную БД вместо того, чтобы делать все свои действия в памяти?

Ваши классы тестов являются дочерними классами django.test.TestCase или unittest.TestCase? Потому что с бд нужно использовать django.test.TestCase...

Похоже, что Django использует реальную базу данных вместо тестовой базы данных при выполнении ваших тестов. Это может произойти, если вы не указали параметр TEST в файле настроек вашего Django проекта.

В вашем файле настроек должен быть словарь TEST, который определяет настройки, используемые при выполнении тестов. Этот словарь должен включать параметр DATABASES, который определяет базу данных, используемую для тестирования.

Например, если вы используете SQLite в качестве базы данных, ваш словарь TEST может выглядеть следующим образом:

TEST = {
    'DATABASES': {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': 'test.sqlite3',
        }
    }
}

Указав параметр TEST в вашем файле настроек, вы можете гарантировать, что Django будет использовать правильную базу данных при выполнении тестов.

Словарь TEST в DATABASES предлагает ряд параметров для настройки вашей >тестовой базы данных. Например, если вы хотите использовать другое имя базы данных, >укажите NAME в словаре TEST для любой данной базы данных в DATABASES.

.

В PostgreSQL USER также потребуется доступ на чтение к встроенной базе данных postgres >

.

https://docs.djangoproject.com/en/4.1/topics/testing/overview/

Возможно, вы можете использовать TestCase для создания БД и использовать setUp и tearDown для создания фиктивной модели следующим образом:

class LocalizedModelsTests(TestCase):
    def setUp(self):
        # Create the dummy model
        with connection.schema_editor() as schema_editor:
            schema_editor.create_model(DummyClass)
        # Create any objects you need for your tests here
        DummyClass.objects.create(name='Test')

    def test_dummy_class(self):
        # Test the DummyClass model here

    def tearDown(self):
        DummyClass.objects.all().delete()
        # Delete the dummy model
        with connection.schema_editor() as schema_editor:
            schema_editor.delete_model(DummyClass)

Дайте мне знать, если это вам поможет.

Похоже, что проблема заключается в том, что ваши тесты модифицируют реальную базу данных, а не создают базу данных в памяти для каждого теста. Это может происходить из-за использования TransactionTestCase, который создает новую транзакцию для каждого теста, позволяя тестам изменять базу данных.

Одним из решений может быть использование TestCase вместо TransactionTestCase и использование аргумента db в ваших тестовых методах, чтобы указать, какую базу данных использовать для данного теста. Например:

class LocalizedModelsTests(TestCase):
    def test_dummy_class(self, db='default'):
        # Code to test the DummyClass model using the specified database

Это создаст базу данных in-memory для каждого теста, позволяя тестам изменять базу данных, не затрагивая фактические данные.

Другим решением может быть использование декоратора @override_settings для указания базы данных TEST в методах тестирования. Например:

from django.test import override_settings

@override_settings(DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}})
class LocalizedModelsTests(TestCase):
    def test_dummy_class(self):
        # Code to test the DummyClass model using the in-memory database

Это отменяет настройки базы данных по умолчанию и использует базу данных в памяти на время проведения теста.

Вернуться на верх