pytest django: невозможно получить доступ к базе данных при разборке приспособления

Мне нужно явно удалить прибор после его использования. Я знаю, что pytest-django по умолчанию удаляет все объекты при разборке, но в данном конкретном случае мне нужно сделать это вручную. Однако, хотя мои тесты помечены как pytest.mark.django_db, я могу создать фикстуру, но не могу удалить ее после строки yield:

import pytest

from tgapps.models import TelegramApp


@pytest.fixture(scope='module')
def some_fixture():

    app = TelegramApp.objects.create(
        session_data=b'\xa2\x8f#',
        app_owner_phone=79856235474,
        app_id=182475,
        app_hash='aad9ab4384fea1af0342b77b606d13b0'
    )
    yield app

    print('deleting object...')
    app.delete()


class TestTelegramServiceObject(object):

    @pytest.mark.django_db
    def test1(self, some_fixture):
        print('Fixture created:')
        print(some_fixture)

это мой тестовый вывод:

============================= test session starts ==============================
platform darwin -- Python 3.6.4, pytest-3.4.0, py-1.5.2, pluggy-0.6.0
Django settings: inviter.settings.staging (from ini file)
rootdir: /Users/1111/_projects/fasttrack/inviter, inifile: pytest.ini
plugins: mock-1.7.1, dotenv-0.1.0, django-3.1.2
collected 1 item
test_example.py E.Fixture created:
<79856235474 - 182475>
deleting object...

tests/api/test_example.py:25 (TestTelegramServiceObject.test1)
@pytest.fixture(scope='module')
    def some_fixture():

        app = TelegramApp.objects.create(
            session_data=b'\xa2\x8f#',
            app_owner_phone=79856235474,
            app_id=182475,
            app_hash='aad9ab4384fea1af0342b77b606d13b0'
        )
        yield app

        print('deleting object...')
>       app.delete()

test_example.py:21: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/Users/1111/.virtualenvs/inviter-WB5rPISo/lib/python3.6/site-packages/django/db/models/base.py:890: in delete
    collector.collect([self], keep_parents=keep_parents)
/Users/1111/.virtualenvs/inviter-WB5rPISo/lib/python3.6/site-packages/django/db/models/deletion.py:221: in collect
    elif sub_objs:
/Users/1111/.virtualenvs/inviter-WB5rPISo/lib/python3.6/site-packages/django/db/models/query.py:276: in __bool__
    self._fetch_all()
/Users/1111/.virtualenvs/inviter-WB5rPISo/lib/python3.6/site-packages/django/db/models/query.py:1179: in _fetch_all
    self._result_cache = list(self._iterable_class(self))
/Users/1111/.virtualenvs/inviter-WB5rPISo/lib/python3.6/site-packages/django/db/models/query.py:53: in __iter__
    results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
/Users/1111/.virtualenvs/inviter-WB5rPISo/lib/python3.6/site-packages/django/db/models/sql/compiler.py:1062: in execute_sql
    cursor = self.connection.cursor()
/Users/1111/.virtualenvs/inviter-WB5rPISo/lib/python3.6/site-packages/django/db/backends/base/base.py:255: in cursor
    return self._cursor()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.backends.postgresql.base.DatabaseWrapper object at 0x1048bf080>
name = None

    def _cursor(self, name=None):
>       self.ensure_connection()
E       Failed: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.

Почему это? и как включить оценку БД при разборке приспособления?


person kurtgn    schedule 24.05.2018    source источник


Ответы (2)


Приспособление db, как упомянул Андреас Профус, ограничено функцией, поэтому здесь это не сработает.

Что вам нужно сделать, это:

@pytest.fixture(scope='module')
def some_fixture(django_db_setup, django_db_blocker):
    with django_db_blocker.unblock():
        app = TelegramApp.objects.create(
            session_data=b'\xa2\x8f#',
            app_owner_phone=79856235474,
            app_id=182475,
            app_hash='aad9ab4384fea1af0342b77b606d13b0'
        )
    yield app
    with django_db_blocker.unblock():
        print('deleting object...')
        app.delete()

django_db_setup гарантирует, что тестовая база данных настроена (и готова) для добавления дополнительных записей. django_db_blocker — это то, что фикстура db использует для разрешения изменений в области действия функции. Причина, по которой его функция ограничена областью действия, заключается в том, что он будет вести себя так, как методы TestCase ведут себя в стандартной среде модульного тестирования, где записи откатываются после каждого теста. Это хорошо, так как изменение записи в одном тесте не изменит результат в другом тесте.

Поэтому будьте очень осторожны при создании фикстур, которые не относятся к области действия функции, так как ваши модификации по умолчанию не будут включены в транзакцию и не будут откатываться. Использование django_db_blocker дает вам доступ к методу django_db_blocker.unblock(), который удаляет блокировку изменения базы данных. Это требуется в ваших приборах с нефункциональной областью видимости.

person Tom    schedule 30.08.2019

Вам нужно потребовать фикстуру db в some_fixture:

def some_fixture(db): ...

person Andreas Profous    schedule 27.06.2019