Search code examples
djangosqlitedjango-unittest

How does django/sqllite3 build database for testing?


Hi I'm attempting to write some unittests for my django web application but I'm running into some database problems when trying to run my tests. I'm using Factory Boy in some places in order to create instances for the tests (https://github.com/dnerdy/factory_boy is the repo) but I'm running into some problems when I attempt to run my tests. I'm getting database errors such as: no such column when I try to run my tests and table already exits errors when I try to run ./manage.py syncdb (I'll include the actual errors below). I'm using the default sqlite3 database settings for testing so the test DB is created to run the tests then destroyed afterward automatically.

Here are the pertinent sections of my settings.py file

if 'test' in sys.argv or 'jenkins' in sys.argv:
DATABASES = {
             'default': {
                         'ENGINE': 'django.db.backends.sqlite3',
                         'NAME': 'test_ndptc'
                         }
             }   

Here is the model that is throwing the error.

class CourseManager(models.Manager):
def get_query_set(self):
    return super(CourseManager, self).get_query_set().order_by('CourseName')

class Course(models.Model):
"""
"""
CourseName = models.CharField(max_length=80)
ShortName = models.CharField(max_length=50)
CourseNumber = models.CharField(max_length=50)
TrainingProvider = models.ForeignKey(TrainingProvider)
TrainingType = models.ForeignKey(TrainingType)
CourseType = models.ForeignKey(CourseType)
ModuleCount = models.IntegerField()
ContactHours = models.CharField(max_length=5)
Certified = models.BooleanField()
Description = models.TextField(null=True, blank=True)
TargetAudience = models.TextField(null=True, blank=True)
Prerequisites = models.TextField(null=True, blank=True)
Requirements = models.TextField(null=True, blank=True)
Icon2d = models.FileField(upload_to='icons/', null=True, blank=True)
Icon3d = models.FileField(upload_to='icons/', null=True, blank=True)
Status = models.IntegerField(null=True)
UpdateUser = models.ForeignKey(User, null=True)
UpdateDate = models.DateField(null=True)
Featured = models.BooleanField(verbose_name='is featured?')

objects = CourseManager()

Here is the factory where the error occurs.

class TestFactory(factory.Factory):
FACTORY_FOR = Test

Course = random.choice(Course.objects.all())
EffectiveDate = '01/01/2012'
Type = random.choice(TestType.objects.all())
Label = 'test_label'
Status = 1
UpdateUser = factory.LazyAttribute(lambda a: UserFactory())
UpdateDate = '01/01/2012'

And finally here is the error that occurs when I run ./manage.py test

Traceback (most recent call last):
File "./manage.py", line 11, in <module>
execute_manager(settings)
File "/usr/local/lib/python2.7/dist-packages/Django-1.3.1-   py2.7.egg/django/core/management/__init__.py", line 438, in execute_manager
utility.execute()
File "/usr/local/lib/python2.7/dist-packages/Django-1.3.1-py2.7.egg/django/core/management/__init__.py", line 379, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python2.7/dist-packages/Django-1.3.1-py2.7.egg/django/core/management/base.py", line 191, in run_from_argv
self.execute(*args, **options.__dict__)
File "/usr/local/lib/python2.7/dist-packages/Django-1.3.1-py2.7.egg/django/core/management/base.py", line 220, in execute
output = self.handle(*args, **options)
File "/usr/local/lib/python2.7/dist-packages/Django-1.3.1-py2.7.egg/django/core/management/commands/test.py", line 37, in handle
failures = test_runner.run_tests(test_labels)
File "/usr/local/lib/python2.7/dist-packages/Django-1.3.1-py2.7.egg/django/test/simple.py", line 358, in run_tests
suite = self.build_suite(test_labels, extra_tests)
File "/home/brandon/course-management/Testing/runner.py", line 17, in build_suite
suite = unittest.defaultTestLoader.loadTestsFromNames(test_labels)
File "/usr/lib/python2.7/unittest/loader.py", line 128, in loadTestsFromNames
suites = [self.loadTestsFromName(name, module) for name in names]
File "/usr/lib/python2.7/unittest/loader.py", line 91, in loadTestsFromName
module = __import__('.'.join(parts_copy))
File "/home/brandon/course-management/Testing/admin_tests.py", line 5, in <module>
from Testing.Factories.course_factory import *
File "/home/brandon/course-management/Testing/Factories/course_factory.py", line 19, in <module>
class TestFactory(factory.Factory):
File "/home/brandon/course-management/Testing/Factories/course_factory.py", line 22, in TestFactory
Course = random.choice(Course.objects.all())
File "/usr/lib/python2.7/random.py", line 274, in choice
return seq[int(self.random() * len(seq))]  # raises IndexError if seq is empty
File "/usr/local/lib/python2.7/dist-packages/Django-1.3.1-py2.7.egg/django/db/models/query.py", line 82, in __len__
self._result_cache = list(self.iterator())
File "/usr/local/lib/python2.7/dist-packages/Django-1.3.1-py2.7.egg/django/db/models/query.py", line 273, in iterator
for row in compiler.results_iter():
File "/usr/local/lib/python2.7/dist-packages/Django-1.3.1-py2.7.egg/django/db/models/sql/compiler.py", line 680, in results_iter
for rows in self.execute_sql(MULTI):
File "/usr/local/lib/python2.7/dist-packages/Django-1.3.1-py2.7.egg/django/db/models/sql/compiler.py", line 735, in execute_sql
cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/Django-1.3.1-py2.7.egg/django/db/backends/sqlite3/base.py", line 234, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.DatabaseError: no such column: Course_course.ShortName

Solution

  • I think that random.choice is running on a empty list. I think you could use a lazy attribute, e.g.

    @factory.lazy_attribute
    def course(a):
        """ Creates a course if none exist
        """
        if Course.objects.count() == 0:
            course = CourseFactory()
            return course
        else:
            return random.choice(Course.objects.all())