Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

force Django tests to write models into database

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.

like image 579
eLRuLL Avatar asked Jan 25 '18 22:01

eLRuLL


2 Answers

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.

like image 134
hoefling Avatar answered Oct 11 '22 03:10

hoefling


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

like image 32
Ghariani Mohamed Avatar answered Oct 11 '22 04:10

Ghariani Mohamed