Posts Tagged ‘test-driven development’

Test-driving Django-application development

February 8th, 2009
3
Digg me

Test-Driven Development (TDD) is something that I’m currently really excited about. It’s nothing new in the world of software development, but it’s very new to me. I have read lots about it but I haven’t been able to start experiencing with it at work for various reasons (excuses!). Anyway, finally I decided to start a personal project of my own, where I would begin to start learning TDD in practice. I chose to re-create a webstore-application I had previously written in PHP many years ago. I guess it would’ve been easier to start with something else than web-development but I’ve been playing around with a webframework called Django, which is excellent, and I figured I should combine those two. For a second I thought about using some PHP framework like Zend, but I just prefer Python.

I started by googling, if someone had used TDD while developing Django-applications. There was not much to be found, and for the most part it was outdated. However, I found some interesting blog posts about testing in general with django. I especially found small django tips from one newbie to another by Adam Smith very useful. I had worked with Django before and I knew the basics of TDD so low search results didn’t matter much. I was ready to begin.

The first thing I did was to set-up the development environment. I created the Django-project and the app inside it. I guess there are many ways you could Test-Drive in this situation but I wanted to use Django’s way of testing. So basically this means that I need to run the tests by executing “manage.py test” within my project. This will sniff the insides of django-applications for tests.py file (and models.py with tests inside that). The result of the command is the same you get from standard Python unittests runs. Of course you can specify the app with the command, but in the beginning there is just one app to begin with, so it was ok to run all tests. Everything so far, was created by Django, including example tests.py file within the application. You can use Python Unittest or Docstring frameworks. I chose Unittest, since I’m more familiar with the xUnit frameworks such as JUnit. I think there was a mention in the Django docs, that you can also use other test tools.

I experimented a little with the Python interactive interpreter on how the tests work. At this time I started to think that having just one tests.py is going get crowded pretty soon so I created a module my_tests under the application and created model_tests.py and view_tests.py under it. I figured I wanted to keep the views as compact as possible and write the logic to either to the model classes or somewhere else, which would be decided later. For now, model and view tests should be enough to get me started. I also wanted to separate my test files from the actual code. Here is a sketch of my project configuration:

Django-project/
--settings.py
--/my_webstore_application/
----views.py
----models.py
----tests.py
------/my_tests/
--------model_tests.py
--------view_tests.py
--------test_utils.py

The tests.py is just a collection of suites:

import unittest
import my_tests.view_tests
import my_tests.model_tests
 
def suite():
    suite1 = unittest.TestLoader().loadTestsFromModule(my_tests.view_tests)
    suite2 = unittest.TestLoader().loadTestsFromModule(my_tests.model_tests)
    alltests = unittest.TestSuite([suite1, suite2])
    return alltests

I also created a run-configuration for Eclipse, so the RED-GREEN-REFACTOR –cycle would be as fluent as possible. Here are some of the first tests I wrote (These are actually somewhat refactored, but the basic idea has remained):

*model_tests.py

from django.test import TestCase
from django.core.files.images import ImageFile  
from webstore.models import Product, Category, SubCategory, Image
from utils import *
 
 
class ProductTest(TestCase):
    def test_create_product(self):
        product = Product(name='test product 1', price="15.50", 
                          description='What a great product!')
        self.assertEquals(product.name, str(product))
 
class CategoryTest(TestCase):
    def test_create_category(self):
        category = Category(name='test category 1')
        self.assertEquals(category.name, str(category))

*view_tests.py

from django.test.client import Client
from django.test import TestCase
from utils import *
from merinostore.webstore.models import *
 
class ProductTest(TestCase):
    def setUp(self):
        self.client = Client()
        self.category = Category(name='test category 1')
        self.category.save()
        self.subcategory = SubCategory(name='test subcategory 2')
        self.subcategory.save()
        self.product = Product(name='test product 1', price='15.50', 
                               description='What a great product!',
                               category=self.category, subcategory=self.subcategory)
        self.product.save() 
 
    def test_list_products_template(self):
        response = self.client.get('/products/')
        self.failUnlessEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'product/list_products.html')
 
    def test_list_products(self):
        create_products(self.category, amount=10)
        response = self.client.get('/products/')
        self.failUnlessEqual(len(response.context[1]['products']), 11)

So I started with the models. I soon figured out that at this point there is virtually no code created by me in models so I stopped doing those and concentrated on the view tests. If the models are broken, they cannot be used anywhere. Later I started to write some more model tests, as I defined my own functions for them. As you can see, I use the Django helpers such as Client, which can be used to emulate the browser. I also use Django’s own TestCase class for assertions.

I was a little bit concerned about testing through views. This means I deal with real instances of the models, which exist in the database. It isn’t unit testing anymore if the tests hit the database, right? Luckily, Django’s test system is pretty good by default. It creates in-memory sqlite database for testing and you can even use fixtures with that. I just couldn’t find any reason for doing any heavier separation between the code and the database as running the tests were fast enough for me. Webstore application itself is mostly just about displaying items from the database. Of course, with the order handling and such tasks, I still plan to keep the logic separated from the views as much as possible. I figured as long as I write tests in order to drive design, it’s good.

I’m still in the process of developing the application, I have just finished the first feature, which is displaying of product list by categories (I copied the html stuff from the old store). What I didn’t do is test drive the templates. It just feels too much work, but I guess I could try that one as well.

I’m quite happy about the whole process in generally. At first I felt that I was proceeding very slowly, but at the same time it felt surprisingly good to get the GREEN showing up. I also created a simple script to import the data (products for now) from my previous webstore implementation, and I didn’t use TDD for that. The reason I didn’t Test-Drive is because I felt the script is so small and will be used only once so I wanted just to be done with it. It turned out to be hideous, and now I feel bad I didn’t TDD it (I think I’m going to rewrite that as well for practice). So I guess I’m learning something!

I’ll post more on the subject as I proceed or get the application ready. I’m sure that my tests aren’t very good and I’m doing many things wrong, but in order to better myself I hope I get some feedback. Till next time!

Software development as a craft

December 10th, 2008
4
Digg me

Most people don’t understand what software development really is. They think of computers, automation, and repetitive dull work. Maybe you’ve heard the phrase “even monkey could do it”. Hell, I’ve used that one myself describing my work. Even many of us who are in the industry, don’t seem to grasp the true nature of it. Not so long ago, I didn’t have a clue myself, but recently I’ve started to look things differently. I’m still in the dark but I’ve seen a glimpse of light. Does this sound like a cliché yet? ;)

As a software developer, it’s all about your own attitude, self-respect even. More precisely, it’s about being professional. Sure, you can be the code monkey and not care about what you do, how you do it or in what environment you do it. This is how most people think, and this is exactly the reason why software developer as profession is not appreciated in a way, as it should be. If you think about it, this applies exactly the same in almost any profession. What makes software development special is that it’s not merely about engineering. It’s more than that. It’s an art. I stumbled across this post by David Christiansen, which is about how professionals perceive software development, or how it should be perceived. By now, you should have a clue what I think about it, at least from the topic of this post…

I’ve come to think software development as a craft. This is not something that I’ve made up myself, obviously, but it something that I’ve really started to relate to. There are many great blogs and articles about the subject, and here is one of them: http://blog.8thlight.com/articles/2008/9/22/definition-of-software-craftsman. There the author Micah gives a good definition of software craftsman and software development as a craft. I’m still in the process of feeling out about the whole Apprentice – Journeyman – Master thing, but I’m starting to like it. Anyway, what Micah says is: “A craftsman takes pride in his work an strives to do the best job he can. He believes that writing good software requires skill and careful attention. That software is not something that can be manufactured nor can it be delivered faster by merely adding more bodies.” I’m a craftsman. I’m might be just in the beginning of my path, an apprentice, but this is something I really believe in.

There is a very entertaining and good series of writings about software craftsmanship by Robert C. Martin, or Uncle Bob if you will. Go to http://objectmentor.com/resources/publishedArticles.html and select Craftsman from published articles topic list. It’s a very long story but it’s worth it. That series is actually the first contact for me about software craftsmanship. It also introduces some good sw-practices such as pair programming and TDD. 

I come from a school where software development is first and last defined as a business. I wasn’t supposed to get involved in the actual development and coding. But I did, and it took me a long time to change my attitude towards it. I always liked coding but I never pursued it as a career. Now, as I said before, my whole world is changing. I have always valued humanistic sciences and arts & crafts (I still do!). Now I’m starting to see that same value in software development, which I used to see only from the business point of view. I have to admit, this is a change I welcome with open arms. Even though I’m not a senior developer, not very experienced and not very skillful, I’m still able to notice that many developers around me don’t give a crap. They don’t value the work they do and they don’t value themselves. I want to do something to change that.

One last note, when I talk about software development, I don’t mean just coding, but everything from project management to testing. It’s all good. :)

Test-Driven Development

September 5th, 2008
2
Digg me

Writing tests is pain because your code is not written to be testable. Why not try something called Test-Driven Developement?

Example: You need software which involves dogs… :) So you probably need a class called Dog. Instead of writing the class first, try to imagine what you would like the class to do. Don’t just imagine it; write a test which demonstrates how you want your dog to act.

class DogTest(unittest.TestCase):
    def testBark(self):
        dog = Dog()
        self.assertEqual('wuh', dog.bark())

You run the test and see it fail. Obviously, since there is no Dog yet! What you have done is that you’ve made a design decision, that you wan’t the dog object to bark by calling its bark method. Now you only need to implement it, and it’s a breeze since you already have the test to back it up:

class Dog():
    def bark(self):
        return 'wuh'

Congrats.. You’re test driving! Simple, isn’t it?

For more information try google or some of these links:
http://www.agiledata.org/essays/tdd.html
http://blog.objectmentor.com/articles/2007/07/17/testing-will-challenge-your-conventions
http://tech.groups.yahoo.com/group/testdrivendevelopment/
http://www.testdriven.com