pytest-django icon indicating copy to clipboard operation
pytest-django copied to clipboard

Database fixtures are run when they shouldn't be for SimpleTestCase unit tests

Open w0rp opened this issue 7 years ago • 8 comments

pytest-django uses a function internally for checking if a test is a Django test case class, named is_django_unittest. This class is used to determine if database setup is needed or not. This is implemented with an issubclass check for SimpleTestCase. However, the Django documentation states the following:

SimpleTestCase disallows database queries by default. This helps to avoid executing write queries which will affect other tests since each SimpleTestCase test isn’t run in a transaction.

See here: https://docs.djangoproject.com/en/1.10/topics/testing/tools/#django.test.SimpleTestCase.allow_database_queries

If you write a unit test in a TestCase class which inherits SimpleTestCase, where allow_database_queries is set to False, which is the default, you will hit problems when you have a fixture defined like so in your conftest.py file:

@pytest.fixture(autouse=True)
def setup_db_tenant(db):
    # ... Create something in the database here ...

The fixture will be run, and database access will be done, and then Django will print the following error message: (Where YourClassNameHere is whatever your class name is for your test case.)

AssertionError: Database queries aren't allowed in SimpleTestCase. Either use TestCase
or TransactionTestCase to ensure proper test isolation or set 
YourClassNameHere.allow_database_queries to True to silence this failure.

w0rp avatar Mar 27 '17 16:03 w0rp

Should pytest-django behave like if the db fixture would not have been requested then? Or should it switch the flag on SimpleTestCase to allow for access?

blueyed avatar Mar 27 '17 17:03 blueyed

https://github.com/pytest-dev/pytest-django/blob/master/pytest_django/plugin.py#L383 I think my problem actually lies here. The fixture scoped to a class calls getfixturevalue(request, 'django_db_setup'), which sets up the database, including some tests which don't need database access.

I'm not sure if there is an existing fixture which will let me run some database setup code for each function, only if database setup is needed. Generally, I want to automatically only create a database when running at least one test which needs database access. My project now has a conftest.py file which does this, but it requires rewriting a few fixtures which come with this module.

I ended up writing an if statement with request.getfixturevalue('db') to implement a function-scoped fixture for database setup.

w0rp avatar Mar 27 '17 19:03 w0rp

I think I realised what could be done for potentially supporting function-scoped fixtures which conditionally do database setup. If db results in a value which could be simply True or False, or maybe some object or None, you would be able to write this:

@pytest.fixture(autouse=True)
def setup_whatever(db):
    if db:
        do_some_database_setup()

I think there are two separate matters here.

  1. A subtle bug with the built-in session-scoped database setup being done some times where it isn't needed. _django_setup_unittest calls django_db_setup when your tests don't need database access.
  2. A feature request for a "conditional database setup" fixture, described above.

Feel free to split this into two separate issues, etc.

w0rp avatar Mar 28 '17 09:03 w0rp

I ran into this same problem just now. My conftest.py contains django_db_setup fixture which is always ran. Regardless of the sort of test I'm trying run. In this case a testcase inherting from SimpleTestCase. And since it's part of a git push hook, it should be fast as possible, not doing anything in the database. Just a test to see if we had to ran makemessages or not.

Would be nice to have a good solution for this.

puittenbroek avatar Sep 12 '18 08:09 puittenbroek

see also #13 "Easy fixture loading"

westurner avatar Nov 12 '18 20:11 westurner

How does #13 help NOT run fixtures for SimpleTestCase @westurner ? :)

puittenbroek avatar Nov 13 '18 07:11 puittenbroek

A standard way to do this could solve for both use cases.

On Tuesday, November 13, 2018, Peter Uittenbroek [email protected] wrote:

How does #13 https://github.com/pytest-dev/pytest-django/issues/13 help NOT run fixtures for SimpleTestCase @westurner https://github.com/westurner ? :)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/pytest-dev/pytest-django/issues/472#issuecomment-438166561, or mute the thread https://github.com/notifications/unsubscribe-auth/AADGy7YcFaUs9S5PtlRAl4mh-jOyLFg3ks5uunchgaJpZM4Mqis5 .

westurner avatar Nov 13 '18 12:11 westurner

Bumping this. I ran into a similar issue, even without a default fixture in conftest.py. I have an existing project with some SimpleTestCase subclasses that don't perform any db operations. The tests run fine with python manage.py test. With pytest, they fail with the following error:

django.test.testcases.DatabaseOperationForbidden: Database queries to 'default' are not allowed in SimpleTestCase subclasses. Either subclass TestCase or TransactionTestCase to ensure proper test isolation or add 'default' to apps.pages.tests.HomepageTests.databases to silence this failure.

wjh18 avatar Sep 22 '22 16:09 wjh18