Я изо всех сил пытаюсь преобразовать тесты на основе тестов Django в pytest.
Я ожидал, что положить
import pytest
pytestmark = pytest.mark.django_db
в последний модуль трассировки стека, принадлежащий моему коду (lib/frontend/decorators.py)
смягчил бы это, но это не так. Включение его во все четыре моих модуля в трассировке стека тоже не помогло.
Есть ли способ глобально разрешить доступ к базе данных в pytest-django?
vagrant@vagrant-ubuntu-trusty-64:/vagrant$ pytest
== test session starts ==
platform linux2 -- Python 2.7.6, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
Django settings: patient.settings (from ini file)
rootdir: /vagrant, inifile: pytest.ini
plugins: django-3.0.0, pythonpath-0.7.1
collected 265 items / 2 errors
[...]
_ ERROR collecting lib/tests/report/testfunc.py _
lib/tests/report/testfunc.py:6: in <module>
from report.func import generate_report_filename
lib/report/func.py:29: in <module>
from frontend import chart
lib/frontend/chart.py:294: in <module>
@pytest.mark.django_db
lib/frontend/decorators.py:20: in decorator
if Site.objects.get_current().id in (allowed_site_ids):
/usr/local/lib/python2.7/dist-packages/django/contrib/sites/models.py:60: in get_current
return self._get_site_by_id(site_id)
/usr/local/lib/python2.7/dist-packages/django/contrib/sites/models.py:39: in _get_site_by_id
site = self.get(pk=site_id)
/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py:127: in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
/usr/local/lib/python2.7/dist-packages/django/db/models/query.py:328: in get
num = len(clone)
/usr/local/lib/python2.7/dist-packages/django/db/models/query.py:144: in __len__
self._fetch_all()
/usr/local/lib/python2.7/dist-packages/django/db/models/query.py:965: in _fetch_all
self._result_cache = list(self.iterator())
/usr/local/lib/python2.7/dist-packages/django/db/models/query.py:238: in iterator
results = compiler.execute_sql()
/usr/local/lib/python2.7/dist-packages/django/db/models/sql/compiler.py:838: in execute_sql
cursor = self.connection.cursor()
/usr/local/lib/python2.7/dist-packages/django/db/backends/base/base.py:162: in cursor
cursor = self.make_debug_cursor(self._cursor())
/usr/local/lib/python2.7/dist-packages/django/db/backends/base/base.py:135: in _cursor
self.ensure_connection()
E Failed: Database access not allowed, use the "django_db" mark to enable it.
Ну, вы всегда можете создать приспособление для автоматического использования, например
@pytest.fixture(autouse=True)
def enable_db_access(db):
pass
в твоем конкурсе
Ответ @enkore - это путь. Я только что добавил FAQ в документацию:
http://pytest-django.readthedocs.io/en/latest/faq.html#how -can-i-give-database-access-to-all-my-tests-without-the-django-db-marker
Модуль, который я импортирую в тесте, подключается к БД во время импорта. Как включить глобальный доступ к БД, чтобы он уже был разрешен во время тестовой коллекции? Спасибо!
@Telofy Вы когда-нибудь решали проблему маркировки импорта с доступом к БД? Есть такая же проблема...
Извините, но способ работы Django (и pytest-django) не может быть надежным. Единственное правильное решение — просто не выполнять запросы к базе данных во время импорта. pytest-django построен на основе системы фикстур pytests, и pytest-django не может гарантировать, что фикстуры запускаются перед импортом.
Смотрите мой комментарий здесь для более подробного объяснения этой проблемы:
https://github.com/pytest-dev/pytest-django/issues/499#issuecomment -322056315
Просто переписать всю платформу компании, чтобы избежать этих запросов, не в моих силах и времени. Мое решение — очень уродливое исправление обезьяны в conftest.py:
from pytest_django.plugin import _blocking_manager
from django.db.backends.base.base import BaseDatabaseWrapper
_blocking_manager.unblock()
_blocking_manager._blocking_wrapper = BaseDatabaseWrapper.ensure_connection
Я также использую этот декоратор (в сочетании с @pytest.mark.django_db
), чтобы затем убедиться, что тесты не выполняются в неправильной базе данных, потому что это было немного сложно предсказать:
def assert_test_db(func):
@wraps(func)
def wrapper(*args, **kwargs):
assert connection.settings_dict['NAME'] == 'test_kf_server', connection.settings_dict
return func(*args, **kwargs)
return wrapper
Спасибо за пример @Telofy - это действительно полезно. Я также хотел бы избежать переписывания всей нашей кодовой базы!
Выполнение запросов к базе данных во время импорта не только приведет к плохим тестам pytest, но и вызовет проблемы в других частях, которые будет трудно отследить. У тебя будут плохие времена.
Вам не нужно переписывать всю кодовую базу, вы можете обойти это, используя ленивые методы/свойства. Код, который не устанавливает соединение, пока не будет запрошено значение. Также будет работать передача только наборов запросов без оценки. Избегайте таких вещей, как счет и т. д.
Самый полезный комментарий
Ну, вы всегда можете создать приспособление для автоматического использования, например
в твоем конкурсе