Code


Version 3 (modified by Carl Karsten <carl@…>, 7 years ago) (diff)

--

Unit test tools

Disclaimer: I am the author of nose (http://somethingaboutorange.com/mrl/projects/nose).

Test runners like nose and py.test make writing and running unittests easier, and they also make setting up your django enviroment for testing fairly painless. With either package, you can write module-level fixtures (setup/teardown) to install your app models before you run your tests and get rid of them after you're done. Here's a simple example, using sqlite in memory for the test database:

basic test_settings.py:

DEBUG = True
TEMPLATE_DEBUG = DEBUG
DATABASE_ENGINE = 'sqlite3'
DATABASE_NAME = ':memory:'
INSTALLED_APPS = ( 'your.app', )

tests.py

def setup(module):
    os.environ["DJANGO_SETTINGS_MODULE"] = "your.app.test_settings"
    from django.core import management
    from django.db.models.loading import get_app
    try:
        management.install(get_app("your.app"))
    except SystemExit:
        pass

def teardown(module):
    from django.db import connection
    # explicit disconnect to destroy the in-memory db
    connection.close()

# write your tests

If you want to use a persistent db for testing, you'll probably want to follow the lead of runtests.py in django/tests and drop your test database when you're done with it.

Doctest tools

When writing doctests, creating model classes in the doctest is a natural thing to want to do, but it can be hard to get just the right incantation to create the test models' database tables, especially if you have other apps in your test settings. This function can make things quite a bit easier, as its own doctest demonstrates:

def create(module_name, *models):
    """Create tables for a group of models in the current db. This
    makes it a bit easier to create django models in doctests.

    You have to have set up your django.settings, etc, properly
    beforehand, of course. But assuming that is done, you can use
    create to create test models in fake modules like so:

    >>> class Baz(models.Model):
    ...    name = models.CharField(maxlength=10)
    ...    def __repr__(self):
    ...        return self.name
    ...    class Meta:
    ...        app_label = 'baz'
    >>> create('foo.bar.baz.models', Baz)
    >>> b = Baz(name='a baz')
    >>> b.save()
    >>> Baz.objects.all()
    [a baz]

    Take special care with the app_label setting. It must be present,
    and it must match the 2nd to last part of the fake module name
    passed to create.
    """
    
    # create a fake module to hold the models
    import imp
    testmod = imp.new_module(module_name)
    for model in models:
        setattr(testmod, model.__name__, model)
    
    # create them in the db 
    from django.db import connection
    from django.core import management
    sql = management.get_sql_create(testmod)
    cursor = connection.cursor()
    for statement in sql:
        cursor.execute(statement)

See Also: TestingDjango - testing the django framework, as opposed to testing your app.