Opened 3 years ago

Closed 3 years ago

Last modified 3 years ago

#17421 closed Uncategorized (invalid)

./manage.py test trips when unit tests assume a database.

Reported by: dnozay Owned by: nobody
Component: Uncategorized Version: 1.3
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

problem statement:

  • my dev setup uses 'sqlite3' backend with ':memory:' as a database
  • my unit tests assume a database is setup / post_sync signals are done
  • e.g. using fixtures with ContentType

settings:

DATABASES = {
   'default': {
      'ENGINE': 'django.db.backends.sqlite3',
      'NAME': ':memory:'
   }
}

I get the following error:

    return Database.Cursor.execute(self, query, params)
django.db.utils.DatabaseError: no such table: django_content_type

it trips on the fixture using contenttypes,

from django.contrib.contenttypes.models import ContentType
from fixture import DataSet, DjangoFixture
#...
class Resource(DataSet):
   class Meta(object):
      django_model = 'resource.Resource'

   class host1:
      id = 1
      resource_type = ContentType.objects.get(model='host')
      resource_id = Host.host1.id

fix:

    def run_tests(self, test_labels, extra_tests=None, **kwargs):
        """
        Run the unit tests for all the test labels in the provided list.
        Labels must be of the form:
         - app.TestClass.test_method
            Run a single specific test method
         - app.TestClass
            Run all the test methods in a given class
         - app
            Search for doctests and unittests in the named application.

        When looking for tests, the test runner will look in the models and
        tests modules for the application.

        A list of 'extra' tests may also be provided; these tests
        will be added to the test suite.

        Returns the number of tests that failed.
        """
        self.setup_test_environment()
-       suite = self.build_suite(test_labels, extra_tests)
        old_config = self.setup_databases()
+       suite = self.build_suite(test_labels, extra_tests)
        result = self.run_suite(suite)
        self.teardown_databases(old_config)
        self.teardown_test_environment()
        return self.suite_result(suite, result)

Change History (3)

comment:1 Changed 3 years ago by dnozay

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

fix for people having this issue:

# testrunner.py
from django.test.simple import DjangoTestSuiteRunner
class EarlyDBSetupTestRunner(DjangoTestSuiteRunner):
   def run_tests(self, test_labels, extra_tests=None, **kwargs):
      """
      Run the unit tests for all the test labels in the provided list.
      Labels must be of the form:
       - app.TestClass.test_method
         Run a single specific test method
       - app.TestClass
         Run all the test methods in a given class
       - app
         Search for doctests and unittests in the named application.

      When looking for tests, the test runner will look in the models and
      tests modules for the application.

      A list of 'extra' tests may also be provided; these tests
      will be added to the test suite.

      Returns the number of tests that failed.
      """
      self.setup_test_environment()
      old_config = self.setup_databases()
      suite = self.build_suite(test_labels, extra_tests)
      result = self.run_suite(suite)
      self.teardown_databases(old_config)
      self.teardown_test_environment()
      return self.suite_result(suite, result)

# settings.py
TEST_RUNNER = 'testrunner.EarlyDBSetupTestRunner'

comment:2 Changed 3 years ago by aaugustin

  • Resolution set to invalid
  • Status changed from new to closed

Your code is doing ORM queries (which translate to SQL queries) at compile time. You shouldn't do that. You can't assume that the database is synchronized at compile time. Even if the import sequence made it work by accident, it would be very unreliable.


A quick way to make the call to the ORM lazy would be:

    @property
    def resource_type(self):
        return ContentType.objects.get(model='host')

(A better solution may exist — I've never tried the fixture library you're using.)

comment:3 Changed 3 years ago by dnozay

thanks.
I was wondering why the db setup and building the suites were inverted, but this explains it all:

"""
      When looking for tests, the test runner will look in the models and
      tests modules for the application.
"""
Note: See TracTickets for help on using tickets.
Back to Top