Home > front end >  pytest-django: allow test to update database
pytest-django: allow test to update database

Time:02-04

I have a lot of little "tests" I use manually, that is, I run them on demand. Some of them I want to alter the database. I have for a long time used pytest for these. (situation is caching production data in dev environment for some specific testing and debugging)

I have been convinced to add pytest-django, which has some great features. It has hijacked my ad-hoc tests; immediately, they can't access or update the database.

Database access and allowing updates is documented and I was quickly able to half solve it: enable database access, update the database during the test. But all my changes are backed out.

My solution to do that may be bad, well obviously it only half works.

I have added this file: conftest.py in what seems to be the correct place (same directory as the tests).

with contents:

import pytest
from django.conf import settings

pytest_plugins = [
    "tests.fixtures.environments",
    "tests.fixtures.initial_data",
]
@pytest.fixture(scope="session")
def django_db_setup():
    settings.DATABASES["default"] = {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'USER': 'django_api_sync',
        'PASSWORD': 'devpassword',
        'NAME': 'django_api_sync',
        'HOST': 'db',
        'PORT': 5432,
    }
    settings.DATABASES["dear_analytics"] ={
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'USER': 'django_api_sync',
        'PASSWORD': 'devpassword',
        'NAME': 'dear_analytics',
        'HOST': 'db',
        'PORT': 5432,
    }



@pytest.fixture
def db_no_rollback(request, django_db_blocker):
    django_db_blocker.unblock()
    request.addfinalizer(django_db_blocker.restore)

and then I decorate my test for example:

@pytest.mark.django_db
def test_summarise_next_available_data(db_no_rollback):
    KeyValueJson.objects.update_or_create(object_uniqueID="aaa_dear_last_sales_update", defaults={"value": "2020-01-01T00:00:00Z"})
    row = KeyValueJson.objects.filter(object_uniqueID="aaa_dear_last_sales_update").first()
    print(row.value) # this works as expected

...

It runs just fine. During execution, it accesses and updates the database, but the database changes are never committed and they are backed out. If I stop execution at the breakpoint and then query the postgresql table, there is no such row. So it looks like there is a transaction going on, and it is being rolled back.

EDIT

Ah, the test works if I remove @pytest.mark.django_db

or if I do

@pytest.mark.django_db(transaction=True)

I don't understand why either of these have this effect.

CodePudding user response:

I think it works when you remove the marker because django tests already have the database access without the marker:

Test classes that subclass django.test.TestCase will have access to the database always to make them compatible with existing Django tests. Test classes that subclass Python’s unittest.TestCase need to have the marker applied in order to access the database.

When you add the marker without specifying Transaction=True, the Transaction is set to False by default:

With transaction=False (the default when not specified), transaction operations are noops during the test.

Reference: https://pytest-django.readthedocs.io/en/latest/helpers.html#pytest.mark.django_db

  • Related