I have been learning about django over the past two weeks or so. I am finally up to the point where I have started learning about its suggested test frameworks. The creators suggest using unittest, which is the standard python unit testing framework. I have liked this aspect of django: even though the core framework was built from ground up, many of its pieces still rely on standard python libraries.
The standard test runner provided by django creates a temporary test database for every test run and deletes it after the tests have completed. I have chosen to use PostgreSQL as my database and creating a new database in there takes longer than creating a simpler in-memory sqlite database. The problem is that django takes the approach of using a single settings file instead of using different ones like Rails’ approach of separate development, production and test settings files. There is a differentiation of setting the DEBUG variable in the settings file, and then relying on that for specifying the different settings. For example…
1 2 3 |
if DEBUG: DATABASE_NAME = "thebitguru_development" DATABASE_HOST = "" |
But there is no easy way to find out if you are in a test environment. A long time ago (2005!) Ian Maurer suggested modifying DJANGO_SETTINGS_MODULE environment variable, but considering that I only wanted to change one parameter (DATABASE_ENGINE) I thought that was an overkill.
I continued looking around and did not really find any good way of doing this so I was own my own to come with an acceptable way. I read through the command that ran the test at django/db/core/management/test.py
, but did not see anything obvious that would help me figure this out in the settings file. After thinking about it for a little while, I finally figured out a way that I could achieve it. Once again, it was python’s “awesomeness” that allowed me to accomplish this. Initially I debated looking back at the stack using traceback, but decided that would also be an overkill. Some more thinking and I ended up with the following code that uses sys.argv.
1 2 3 4 5 6 |
# Use a different database engine if running tests. manage_command = filter(lambda x: x.find('manage.py') != -1, sys.argv) if len(manage_command) != 0: command = sys.argv.index(manage_command[0]) + 1 if command < len(sys.argv) and sys.argv[command] == "test": DATABASE_ENGINE = "sqlite3" |
The above code is fairly simple and accomplishes the goal. A few days ago I had no idea why lambda functions existed, but now it seems that I am using them all over! You can rewrite the above code to set the TEST variable and then use it again and again, kind of like below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# Determine if we are running in the test environment. TEST = False manage_command = filter(lambda x: x.find('manage.py') != -1, sys.argv) if len(manage_command) != 0: command = sys.argv.index(manage_command[0]) + 1 if command < len(sys.argv): TEST = sys.argv[command] == "test" # . . . some code here . . . # Use sqlite if running in test if TEST: DATABASE_ENGINE = "sqlite3" # . . . later in the file . . . if TEST: # set some other variable here |
Please note that I am only planning on using sqlite3 when writing my test cases because I don’t want to wait too long. Once I have the tests finalized then I will switch back to PostgreSQL, because as pointed out in a conversation on IRC, you should really test what you are actually going to use!