Jun 26

I use Mercurial for all my coding projects. Today I hit upon the idea of using mercurial precommit hooks to run django tests before committing. I didn’t really expect it to be so easy :)

I use postgresql on the server, but I found that on win32, running tests with postgresql is excruciatingly slow.

For comparison, 23 tests with postgresql on Vista laptop take about 193 seconds (The same tests take ~14 seconds on my linux vps). With an sqlite in memory database on the same machine they take about 13.5 seconds. Moral of the story: On Windows, use sqlite in memory databases to test django apps.

Ok, so I had to figure out a way to use sqlite only for testing while using postgresql otherwise. I decided to instrument settings.py

_TEST_DB = False
if 'DJANGO_TEST_DB' in os.environ :
    _TEST_DB = True

if _TEST_DB :
    DATABASE_ENGINE = 'sqlite3'
    DATABASE_NAME =  ':memory:'
    DATABASE_USER = ''
    DATABASE_PASSWORD = ''
    DATABASE_HOST = ''
    DATABASE_PORT = ''
else :
    DATABASE_ENGINE   = 'postgresql_psycopg2'
    DATABASE_NAME     = 'project'
    DATABASE_USER     = 'projectdb'
    DATABASE_PASSWORD = 'dbpassword'
    DATABASE_HOST     = ''
    DATABASE_PORT     = ''

Now I thought of using the inprocess Python hooks feature of Mercurial, but it seemed to be too much of a hassle (need to have the hook script in PYTHONPATH), so I decided to write a simple command line script


import os, sys, subprocess
PROJ_DIR = r'C:\Users\Jeethu\code\project'

def main() :
    proj_dir = os.path.normpath(PROJ_DIR)
    os.chdir(proj_dir)
    os.environ['DJANGO_TEST_DB'] = 'True'
    r = subprocess.call(['python','manage.py','test'])
    return r

if __name__ == '__main__' :
    sys.exit(main())

Then simply add 2 lines to the .hg\hgrc file in the repo.

[hooks]
precommit.tests = c:\Users\Jeethu\code\project\hooks\test_hook.py

Hopefully, this will set the incentives right for me to write more tests.

References:
The hgrc manpage
Chapter 10 of the Mercurial Book