Reputation: 8710
I need to explicitly delete a fixture after it is used. I know that pytest-django by default drops all objects on teardown but in this particular case I need to do it manually. However, although my tests are marked as pytest.mark.django_db
, I am able to create a fixture, but unable to delete it after a yield
line:
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)
this is my test output:
============================= 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.
Why is this? and how do I enable DB assess on fixture teardown?
Upvotes: 5
Views: 3355
Reputation: 2016
The db
fixture as mentioned by Andreas Profous is function scoped so that wouldn't work here.
What you need to do is:
@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
ensures the test database is setup (and ready) for additional records to be added. django_db_blocker
is what the db
fixture uses to allow function scoped modifications. The reason why it's function scoped is so that it will behave how TestCase
methods behave in the default unittest framework where the records are rolled back after each test. This is a good thing, it ensures a modification of a record in one test won't change the outcome in other test.
So be very careful when creating fixtures that aren't function scoped as your modifications won't by default be wrapped in a transaction and rolled back. Using the django_db_blocker
gives you hooks into the django_db_blocker.unblock()
method which removes the block from modifying the database. This is required in your non-function scoped fixtures.
Upvotes: 6
Reputation: 1512
You need to require the db
fixture in some_fixture:
def some_fixture(db):
...
Upvotes: 0