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/
**********
  1. # -*- coding:utf-8 -*-  
  2. import os  
  3. os.environ['DJANGO_SETTINGS_MODULE'] = 'YOURAPP.settings'  
  4. from django.test import utils  
  5. from django.conf import settings  
  6. from django.db import connection  
  7.   
  8. database_name = None  
  9.   
  10. def setup():  
  11.     """Setup the various django fixtures."""  
  12.     database_name = settings.DATABASE_NAME  
  13.     utils.setup_test_environment()  
  14.     connection.creation.create_test_db()  
  15.   
  16. def teardown():  
  17.     """Tear down the fixtures and database."""  
  18.     connection.creation.destroy_test_db(database_name)  
  19.     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.
  1. # -*- coding:utf-8 -*-  
  2. from myproject.myapp.models import User  
  3. from nose.tools import eq_  
  4. from django.test import TestCase  
  5.   
  6. from pprint import pprint as pp  
  7.   
  8. class TestUser(TestCase):  
  9.     fixtures = ['user'# load user.json or user.yml fixture to tables for test  
  10.     def setUp(self): # this will be executed before each test method  
  11.         self.users = User.objects.all()  
  12.         # pp("hi")  
  13.   
  14.     def test_fixture(self):  
  15.         eq_(self.users.count(), 10'user count')  
  16.   
  17.     def test_username(self):  
  18.         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.