django-pytest setup_method database issue
Asked Answered
S

1

9

I have the following set up on Ubuntu 14.04:

  • python 2.7.6
  • django 1.7 [though I reproduced the same behaviour with django 1.9 too]
  • pytest-django 2.8.0 [also tested with 2.9.1]
  • pytest 2.7.2 [also tested with 2.8.3]

And the following test code:

import pytest
from django.db import connection

import settings
from pollsapp.models import Question

original_db_name = settings.DATABASES["default"]["NAME"]

@pytest.mark.django_db
class TestExperiment(object):

    def setup_method(self, method):
        # it's not using the "test_" + DATABASE_NAME !
        assert connection.settings_dict["NAME"] == \ 
        settings.DATABASES["default"]["NAME"]
        Question.objects.create(question_text="How are you?")
        # this data remains in the main database
  1. Although the class is marked to use django database, the data created in the constructor arrive in the main (production) database (name taken from settings.py)

  2. Putting the django_db decorator above the setup_method does not make any difference

  3. This data created in the setup_method remain in the main database, are not rolled back as they should be and as they would be if the data creation call was made in the test_case method

  4. This behaviour happens when the test is run on its own. When running it within the test suite, the setup_method db calls fails with: Failed: Database access not allowed, use the django_db mark to enable although the decorator is clearly there (which means that this error message is not to be 100% trusted btw).

pytest is an awesome framework and django-pytest works great if database calls happen from django_db marked test case methods.

It looks like no db interaction should ever be present in special pytest methods such as setup_method, teardown_method, etc. Although the documentation doesn't say anything about it:

https://pytest-django.readthedocs.org/en/latest/database.html

I am getting this behaviour with both Django 1.7 as well as with 1.9 (latest stable).

Here is the link to the whole test module: https://github.com/zdenekmaxa/examples/blob/master/python/django-testing/tests/pytest_djangodb_only.py

Salicylate answered 4/12, 2015 at 13:25 Comment(2)
decorator should be on method, not on class.Meanly
If it is, the doesn't make any difference. And according to the django-pytest documentation, module, class, method or function level are all possible.Salicylate
T
19

Unfortunately, setup_X methods does not play nice with pytest fixtures. pytest-django's database setup is based on pytest fixtures, and therefore it does not work.

I recommend that you make your setup_method an autouse fixture, that requests the db fixture:

@pytest.mark.django_db
class TestExperiment(object):

    @pytest.fixture(autouse=True)
    def setup_stuff(self, db):
        Question.objects.create(question_text="How are you?")

    def test_something(self):
        assert Question.objects.filter(question_text="How are you?").exists()

The error message given by pytest-django is confusing and misleading, I've opened an issue to track/fix this: https://github.com/pytest-dev/pytest-django/issues/297

Telescopium answered 7/12, 2015 at 10:17 Comment(2)
Thanks. Indeed, this works on setup_method as intended but still getting Failed: Database access not allowed, use the "django_db" mark to enable in the same way marked def teardown_method(self, db): Thanks for your explanation, I assumed to refrain from db interactions in the pytest's special methods.Salicylate
setup_X and teardown_X may break at any time. You should use fixtures for all test setting up and tearing down. pytest.org/latest/… describes how you can register a function to run during teardown. It will have proper database access. Please mark the answer as accepted if you're happy with it.Telescopium

© 2022 - 2024 — McMap. All rights reserved.