Monday, October 5, 2009

Test python codes with Django

These days I use Django, a web application framework for python, and I found that the documentation for Django has little description for model tests with unit testing. I usually use Perl and it has fine, simple way of unit testing.
So I wanted to do tests simply like in Perl.

However, there is little information about executing python's tests in a way like the "prove" command in perl. Moreover, there is less documentation for Django.

Then, I found a way which executes python's unit tests for Django models like perl's ones. This method enables you to write model tests in multiple files, not only 'tests.py.' It's cool.
I'll explain this to you.

First, instal "nose" and "rednose" on your machine. You can just do "easy_install nose" and "easy_install rednose."
"nose" is a test framework for python and this includes the "nosetests" command. This executes python tests like the "prove" command in perl.
"rednose" is a plugin for nose and it colors nosetests' output. This certainly makes your tests fun and effective.
Write this config in ~/.noserc, it's useful.
[nosetests]
verbosity=3
nocapture=1
rednose=1

nose: http://somethingaboutorange.com/mrl/projects/nose/
rednose: http://github.com/gfxmonk/rednose/tree

Second, set up your django project for testing. You can put test files in a directory structure like this:
project/yourapp/t/..
-models/..
--user.py
--product.py
"t" directory includes all test files.
You have to put the following code in an __init__.py
see also: http://blog.cerris.com/2008/08/21/fixtures-with-nose/
**********

# -*- coding:utf-8 -*-
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'YOURAPP.settings'
from django.test import utils
from django.conf import settings
from django.db import connection

database_name = None

def setup():
"""Setup the various django fixtures."""
database_name = settings.DATABASE_NAME
utils.setup_test_environment()
connection.creation.create_test_db()

def teardown():
"""Tear down the fixtures and database."""
connection.creation.destroy_test_db(database_name)
utils.teardown_test_environment()


This methods initialize the database for testing so take care that you don't usea production database.
"models" has tests for models. The important point is to put the __init__.py file in this directory. If you don't, error will occur during testing.
The rules for test classes and methods are written in nose documents. See above url.
Here is an example test code.

# -*- coding:utf-8 -*-
from myproject.myapp.models import User
from nose.tools import eq_
from django.test import TestCase

from pprint import pprint as pp

class TestUser(TestCase):
fixtures = ['user'] # load user.json or user.yml fixture to tables for test
def setUp(self): # this will be executed before each test method
self.users = User.objects.all()
# pp("hi")

def test_fixture(self):
eq_(self.users.count(), 10, 'user count')

def test_username(self):
eq_(str(self.users[0]), 'yaotti')


Third, run the tests while executing nosetests.
$ nosetests yourapp/t/model/user.py
It creates tables for tests, runs tests in user.py, displays the results and destroys the tables. That's all!
**CAUTION**
You should execute nosetests in the root directory of your application. If you don't and you use sqlite, the nosetests command can't find your database file.
This is my good way of testing models in django. If you know a better way than this , please tell me.