force Django tests to write models into database
Asked Answered
T

2

7

I am setting up a very simple Django project and with a very simple test like:

def test_name(self):
    t = Thing.objects.create(name='a')
    print(t.id)
    import time
    time.sleep(30)
    self.assertEqual('a', t.name)

The tests passes of course, but the database (TEST database) doesn't get populated with my Thing model information, even though I can actually see its id as you can see my script.

When I connect into the database, the Thing table is always empty (I also saw some comments about it in the documentation).

Now, how can I tell Django to actually populate the data? I am using mysql, and checking the complete logs I see Django is creating a SAVEPOINT before populating data (that is not committed) and once the test passes, it goes back into that previous SAVEPOINT.

I am using:

Django==2.0.1
mysqlclient==1.3.12
pytest==3.3.2
pytest-django==3.1.2

I would like Django to actually populate the TEST database, with the information from my tests and at the end drop that database, that's why I am assuming Django is creating a completely new database just for tests.

Tarra answered 25/1, 2018 at 22:41 Comment(1)
@hoefling thanks for the hint. Yeah but I want something more general, if I could disable that entirely for all the tests, like in the settings file, that would be great.Tarra
M
4

The pendant to the django.test.TransactionTestCase for pure function tests is the marker

pytest.mark.django_db(transaction=True)

from pytest-django. Example (with the sqlite3 backend):

@pytest.mark.django_db(transaction=True)
def test_model_written_to_db():
    obj = MyModel.objects.create(name='foo')
    assert obj.id == 1
    conn = sqlite3.connect('/tmp/mytestdatabase.sqlite3')
    cur = conn.cursor()
    cur.execute("SELECT * FROM backend_mymodel")
    assert len(cur.fetchall()) == 1

If you want to apply the marker automatically to all tests, you can do that with a custom pytest_collection_modifyitems hook. In your conftest.py:

import pytest

def pytest_collection_modifyitems(items):
    for item in items:
        item.add_marker(pytest.mark.django_db(transaction=True))

Now you can remove the pytest.mark.django_db marker from the above test and it will still behave the same.

However, custom hooks or pytest fixtures don't work for the unittest-style testcases subclassing django.test.TestCase, so your best bet would be indeed subclassing django.test.TransactionTestCase, as suggested Ghariani Mohamed in his answer.

Mulkey answered 30/1, 2018 at 23:34 Comment(0)
W
2

if you are using the django TestCase class, which subclasses the TransactionTestCase class, the database will always be reset to the original state.

https://docs.djangoproject.com/en/2.0/topics/testing/tools/#django.test.TestCase

https://docs.djangoproject.com/en/2.0/topics/testing/tools/#django.test.TransactionTestCase

Windfall answered 29/1, 2018 at 23:53 Comment(1)
the closest solution would be for me to use TransactionTestCase for all my tests.Tarra

© 2022 - 2024 — McMap. All rights reserved.