Pytest-django: Wie kann ich den Datenbankzugriff global zulassen, ohne django_db-Marken zu verwenden?

Erstellt am 20. Sept. 2016  ·  8Kommentare  ·  Quelle: pytest-dev/pytest-django

Ich habe Mühe, meine Django-Testläufer-basierten Tests in Pytest umzuwandeln.
Ich würde erwarten, dass das Setzen

import pytest
pytestmark = pytest.mark.django_db

in das letzte Modul des Stacktrace, das zu meinem Code gehört (lib/frontend/decorators.py)
würde dies mildern, tat es aber nicht. Es hat auch nicht geholfen, es in alle vier meiner Module auf dem Stacktrace zu stecken.

Gibt es eine Möglichkeit, den Datenbankzugriff in pytest-django global zuzulassen?

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.

Hilfreichster Kommentar

Nun, Sie können jederzeit ein Autouse-Gerät erstellen, wie zum Beispiel

@pytest.fixture(autouse=True)
def enable_db_access(db):
    pass

in deinem Wettbewerb

Alle 8 Kommentare

Nun, Sie können jederzeit ein Autouse-Gerät erstellen, wie zum Beispiel

@pytest.fixture(autouse=True)
def enable_db_access(db):
    pass

in deinem Wettbewerb

Die Antwort von @enkore ist der

http://pytest-django.readthedocs.io/en/latest/faq.html#how -can-i-give-database-access-to-all-my-tests-without-the-django-db-marker

Ein Modul, das ich in einem Test importiere, verbindet sich zum Zeitpunkt des Imports mit der DB. Wie aktiviere ich den DB-Zugriff global, sodass er bereits während der Testsammlung erlaubt ist? Danke!

@Telofy haben Sie jemals das Problem der Markierung von Importen mit DB-Zugriff gelöst? Habe das gleiche Problem...

Tut mir leid, aber die Art und Weise, wie Django (und pytest-django) funktioniert, ist nicht zuverlässig möglich. Die einzig richtige Lösung besteht darin, während des Imports keine Datenbankabfragen durchzuführen. pytest-django basiert auf dem Fixture-System von pytests und es gibt keine Möglichkeit, dass pytest-django sicherstellen kann, dass Fixtures vor dem Import ausgeführt werden.

Siehe meinen Kommentar hier für eine detailliertere Erklärung dieses Problems:
https://github.com/pytest-dev/pytest-django/issues/499#issuecomment -322056315

Es liegt weder in meiner Macht noch in meinem Zeitbudget, einfach die gesamte Plattform des Unternehmens neu zu schreiben, um diese Anfragen zu vermeiden. Meine Lösung ist super hässliches Affen-Patching in 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

Ich verwende diesen Dekorator auch (in Verbindung mit @pytest.mark.django_db ), um sicherzustellen, dass die Tests nicht in der falschen Datenbank ausgeführt werden, da die Vorhersage etwas kompliziert war:

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

Danke für das Beispiel @Telofy - das ist wirklich nützlich. Ich möchte auch vermeiden, unsere gesamte Codebasis neu zu schreiben!

Erstellen von db-Abfragen zum Importzeitpunkt führt nicht nur zu schlechten Pytests, sondern führt auch zu Problemen in anderen Teilen, die schwer aufzuspüren sind. Du wirst eine schlechte Zeit haben.

Sie müssen nicht Ihre gesamte Codebasis neu schreiben, Sie können es mit faulen Methoden/Eigenschaften umgehen. Code, der keine Verbindung herstellt, bis Sie nach dem Wert gefragt werden. Es funktioniert auch, nur Abfragemengen ohne Auswertung zu übergeben. Vermeiden Sie Dinge wie Zählen usw.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen