Pytest-django: разрешить тестам обновлять базу данных
У меня есть много маленьких "тестов", которые я использую вручную, то есть запускаю их по требованию. Некоторые из них я хочу изменить в базе данных. Долгое время я использовал для этого pytest. (ситуация - кэширование производственных данных в dev-среде для некоторых специфических тестов и отладки)
Меня убедили добавить pytest-django, у которого есть несколько замечательных возможностей. Он захватил мои ad-hoc тесты; немедленно, они не могут получить доступ или обновить базу данных.
Доступ к базе данных и разрешение обновлений документированы, и я быстро смог наполовину решить эту проблему: включить доступ к базе данных, обновить базу данных во время теста. Но все мои изменения отменяются.
Мое решение сделать это может быть плохим, ну очевидно, что оно работает только наполовину.
Я добавил этот файл: conftest.py в, как кажется, правильное место (тот же каталог, что и тесты).
с содержанием:
import pytest
from django.conf import settings
pytest_plugins = [
"tests.fixtures.environments",
"tests.fixtures.initial_data",
]
@pytest.fixture(scope="session")
def django_db_setup():
settings.DATABASES["default"] = {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'USER': 'django_api_sync',
'PASSWORD': 'devpassword',
'NAME': 'django_api_sync',
'HOST': 'db',
'PORT': 5432,
}
settings.DATABASES["dear_analytics"] ={
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'USER': 'django_api_sync',
'PASSWORD': 'devpassword',
'NAME': 'dear_analytics',
'HOST': 'db',
'PORT': 5432,
}
@pytest.fixture
def db_no_rollback(request, django_db_blocker):
django_db_blocker.unblock()
request.addfinalizer(django_db_blocker.restore)
и затем я оформляю свой тест, например:
@pytest.mark.django_db
def test_summarise_next_available_data(db_no_rollback):
KeyValueJson.objects.update_or_create(object_uniqueID="aaa_dear_last_sales_update", defaults={"value": "2020-01-01T00:00:00Z"})
row = KeyValueJson.objects.filter(object_uniqueID="aaa_dear_last_sales_update").first()
print(row.value) # this works as expected
...
Он работает нормально. Во время выполнения он обращается к базе данных и обновляет ее, но изменения в базе данных никогда не фиксируются и отступают. Если я остановлю выполнение на точке останова, а затем запрошу таблицу postgresql, то такой строки не будет. Таким образом, похоже, что происходит транзакция, и она откатывается назад.
EDIT
Ах, тест работает, если я удалю @pytest.mark.django_db
или если я сделаю
@pytest.mark.django_db(transaction=True)
Я не понимаю, почему ни один из них не оказывает такого эффекта.
Я думаю, что это работает, когда вы удаляете маркер, потому что тесты django уже имеют доступ к базе данных без маркера:
Тестовые классы, подклассы django.test.TestCase будут иметь доступ к базе данных всегда, чтобы сделать их совместимыми с существующими Django тестами. Тестовые классы, которые подклассифицируют Python's unittest.TestCase, нуждаются в том, чтобы применить маркер, чтобы получить доступ к базе данных.
Когда вы добавляете маркер без указания Transaction=True, по умолчанию Transaction устанавливается в False:
При transaction=False (по умолчанию, если не указано), транзакция операции во время теста не выполняются.
Ссылка: https://pytest-django.readthedocs.io/en/latest/helpers.html#pytest.mark.django_db