Archive for July, 2008

Unit Testing in Django

Saturday, July 26th, 2008

This article will be based off this bit of documentation:

http://www.djangoproject.com/documentation/testing/

To begin, I would like to give an introduction to unit tests. Unit tests are bits of testing code to test the functionality of your code. The reason why they are helpful is because say you change your model to have a non-null field of something new. You don’t change the controller method that creates the new entry – what happens? It’ll most likely fail. I don’t know about you, but I’d rather catch the tests early, instead of much later and all. This is where unit tests come in. Unit tests help give a bit more measure of success on that your methods actually will work.

They are extremely important.

Django utilizes both doctests, and unit tests. Personally I feel unit tests are a bit better because doc tests can clutter your code, making things a bit harder to read. To start a unit test all you need to do is something like:
from django.test import TestCase
class myTest(TestCase):
def test1(self):

The kicker that got me, and the majority of the reason why I’m posting this is that you absolutely need to have each method definition starting with test. If you have def foo, instead of the above – Your tests WILL NOT RUN I wish the documentation went over that bit of information.

Another important thing with testing is the ability to utilize fixture data. The problem I see is that I don’t want to use the fixture initial_data, because if I do that, then whenever I do a syncdb I may get data I really don’t want for my own development. Personally, I rather have my own fixture just for the unit tests. You can define that like this:

from django.test import TestCase
class myTest(TestCase):
fixtures = ['myfixture.json']
def test1(self):

Another thing I read about, that should be kept in mind that if your tests aren’t found, make sure that you have a models.py in the same directory. If you don’t, then apparently the tests aren’t found. It’s been reported, I don’t know the status of the issue (I haven’t run into the issue quite yet).

Now about functional tests…

Functional tests, as an introduction, is the testing of the flow of your site. For example, if you view the index of your site – do you get an error page? This is important to know, which is why functional tests are there. Unlike unit, this isn’t testing any one particular method – bit more to make sure that if a user was to visit your site in that area, that the behavior is expected.

Definitions for functional tests are exactly that of the unit tests, except a nifty little thing called the django test client. One example of how to use it is like this:

class functionalTests(TestCase):
fixtures = ['myfixture.json']

def testSiteIndex(self):
response = self.client.get(‘/’)
self.failUnlessEqual(response.status_code, 200)

So what this does is load up its own little browser so to speak and visit the index. If it’s successful, then the return is 200 and all is good.

The documentation goes over a bit more on functional tests – including post variables. You can use tests to make sure that posting something to the site works. Also, logging in and out and content checks also work.

I think unit testing, in general, is really quite good with DJango. I’ve read a few posts about how horrible it was, but I really feel it’s right in line with what Rails can do. There aren’t many nifty projects quite yet though, like automated unit testing and all – but that’ll come in time. There is one article I started reading about automated unit testing with python, I’ll post more on that later.

Proposal for splitting out models from a singular file

Sunday, July 6th, 2008

If you follow the Django tutorial, we have the following basic files:
app/models.py
app/views.py

If you’re familiar with Rails, you have something like
models/model1
models/model2

I was discussing a bit in the #django chat room a few days ago about this, and the argument that was given is that if you’re going to have that large of models, that splitting the application out is a good idea. I agree with this a lot, actually. You can have a different application, that doesn’t actually get mapped to a view. So…you can have something like a blogs application, and a blog_comments application if you so desire. Personally I wouldn’t go this far….

What I feel is better, in the case of the blog application is to have the blog, comments, subject, and so on as individual models. This is what the tutorial already does. The problem I see, though, is that if you put more of your business logic into the model (where it should be, to follow DRY), then these models can get extremely large. There is a way around all this actually.

You can create a models directory, within your application directory, and split out the large model into separate models. The way I refactored the Cab application recently was to do something like:
cab/models/__init__.py – I’ll describe this later
cab/models/Bookmark.py
cab/models/Language.py

In the __init__.py, you need to include each of the separate models, for example:
from Bookmark import Bookmark
from Language import Language

Personally, while it’s annoying to edit the __init__.py file all the time, I find this much cleaner. I feel that perhaps if I have some time I’ll create a function for manage.py so that it can auto-generate this file on demand. That would save a whole lot of work for me.