Home > Software engineering >  pytest django giving me a database error when fixture scope is 'module'
pytest django giving me a database error when fixture scope is 'module'

Time:05-17

I have the following inside conftest.py

@pytest.mark.django_db
@pytest.fixture(scope='module')
def thing():
    print('sleeping')  # represents a very expensive function that i want to only ever once once per module
    Thing.objects.create(thing='hello')
    Thing.objects.create(thing='hello')
    Thing.objects.create(thing='hello')

Inside tests.py

@pytest.mark.django_db
def test_thing(thing):
    assert models.Thing.objects.count() > 1

@pytest.mark.django_db
def test_thing2(thing):
    assert models.Thing.objects.count() > 1


@pytest.mark.django_db
@pytest.mark.usefixtures('thing')
def test_thing3():
    assert models.Thing.objects.count() > 1

All three tests throw the same error: RuntimeError: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.

I've tried using scope='session' / scope='class' / scope='package' / scope='module' -- the only one that works is `scope='function' which defeats the purpose of what I'm trying to accomplish. I want to be able to create all these items ONCE per module, not once per test.

Note: I ran into this issue with a large code base and created a new django project with a single app to test and see if the problem was the existing test code, and it failed on a standalone test also. Tested it with both postgres and sqlite; doesn't seem like a database issue.

Not that it matters, but the models.py

class Thing(models.Model):
    thing = models.CharField(max_length=100)

CodePudding user response:

You can request db fixture in fixture instead. It is described in docs in first note.

If you want access to the Django database inside a fixture, this marker may or may not help even if the function requesting your fixture has this marker applied, depending on pytest’s fixture execution order. To access the database in a fixture, it is recommended that the fixture explicitly request one of the db, transactional_db, django_db_reset_sequences or django_db_serialized_rollback fixtures. (emphasis mine)

# conftest.py

@pytest.fixture(scope='module')
def thing(db):  # Use "db" fixture
    print('sleeping')  # represents a very expensive function that i want to only ever once once per module
    Thing.objects.create(thing='hello')
    Thing.objects.create(thing='hello')
    Thing.objects.create(thing='hello')

CodePudding user response:

Ok, turns out this is a known limitation, and it's somewhat documented here. If you want to solve this issue, and get away from this bug:

@pytest.mark.django_db
@pytest.fixture(scope='module')
def thing(django_db_setup, django_db_blocker):
    del django_db_setup  # Cannot be used with usefixtures(..) it won't work
    with django_db_blocker.unblock():
        print('sleeping')
        Thing.objects.create(thing='hello')
        Thing.objects.create(thing='hello')
        Thing.objects.create(thing='hello')
        Thing.objects.create(thing='hello')
        yield
  • Related