Test Driven Development in Python

By : Anoop Thomas Mathew

We can either prevent bad things from happening or fix it, once it is detected.

It is your choice to select any of these methodology, while developing a software. You can either develop based on a test driven process or the recover from a fiasco with tests.

Test driven development, as the name suggests, is development based on tests. Tests for core features are written prior to the implementation for the expected output, and then necessary modules are written to satisfy the needs define the


Advantages of Test Driven Development

  • application is determined by using it
  • written minimal amount of application code
  • total application + tests is probably more smaller
  • simpler, stand-alone, minimal dependencies
  • tends to result in extensible architectures
  • instant feedback
  • future development won't break existing features.

About Test Driven Development

  • Write tests for the use case Run it
  • (make sure it fails and fails
  • miserably) Write code and implement
  • the required functionality with relevant level of detail
  • Run the test
  • Write test for addition features
  • Run all test Watch it succeed. Have a cup of coffee !

Basic Unittest


import unittest
class MyTest(unittest.TestCase):
    def testMethod(self):
        self.assertEqual(hello(5), 5, "Hello din't return 5.")

if __name__ == '__main__':
    unittest.main()

To write a basic unittest in python, is pretty straight forward. The code above is self explainatory. It is trying out hello function, and expected output is given as 5. If somehow, hello() din't return 5, then the error message is printed to the console.

Now, let's try writing the function hello to satisfy the test.

def hello(value):
    return 5

or

def hello(value):
    return value

This is a problem!

The problem is, how to select the best. Solution is, to get the tests more detailed and covering more test cases to satisfy the requiements of the function. As we have more precise requirements in the tests, we can easily rule out either the more complex solutions or the more simpler solutions, and get the perfect balance between development and requirement.

One thing to keep in mind while doing Test Driven Development is, Don't Overkill. Just write tests for the core features expected, and write it expecting all the complete range. For example, if it is a multiplication function, make sure that you need make sure that you handle strings as you need it.

Another Example

An example for doing test driven development for greater than function is given below.

The requirement is crazy, to compare the ascii sum of the text string if argument is a string.

The Test

import unittest
from demo import Greater
class DemoTest(unittest.TestCase):
    def test_number(self):
        comparator = Greater()
        result = comparator.greater(10,5)
        self.assertTrue(result)
    def test_char(self):
        comparator = Greater()
        result = comparator.greater('ABCabcxyz', 'ABa')
        self.assertTrue(result)
    def test_char_equal(self):
        comparator = Greater()
        result = comparator.greater('4', 3)
        self.assertTrue(result)
if __name__ == '__main__':
    unittest.main()

Now the Code

class Greater(object):
    def greater(self, val1, val2):
        if type(val1) ==str or type(val2) == str:
           val1 = str(val1)
           val2 = str(val2)
           sum1 = sum([ord(i) for i in val1])
           sum2 = sum([ord(i) for i in val2])
           if sum1 > sum2:
               return True
           else:
               return False
        if val1>val2:
            return True
        else:
            return False

The function returns True or False, based on the ascii values if any of the argument is string, else give the greater.

Note: A presentation on the topic is available http://www.slideshare.net/atmb4u/test-driven-development-in-python

TL; DR: Write tests to satisfy requirements, then write code. Have a peaceful life !

Have a happy Test Driven Development!!!


Can we help you build amazing apps? Contact us today.

Comments

Harry Percival

Hey, always good to see others preaching the cult of TDD! Here's my own attempt at a contribution: http://www.tdd-django-tutorial.com/ - it's a step-by-step tutorial for how to use django, from scratch, using full TDD from the beginning, including browser automation tests with Selenium...

commmenttor
jlennon

It's great that you are taking your time and teaching TDD to beginners however a pet peeve of mine is when I see bad practices in such tutorials.

First you should not use type to find out the class of a value. You should use isinstance.

Also writing all of those lines doesn't make sense:

if sum1 > sum2:
return True
else:
return False

You should just write:

return sum1 > sum2

And the same below for val1, val2.

I know that these have nothing to do with the topic in hand and even work fine but IMHO if you are targeting newbies you should strive to use best practices and language idioms as much as possible. Sometimes it is difficult to "unlearn" bad practices that you pick up along the way.

Please don't take this the wrong way. It is intended as constructive criticism :)

All the best ...

commmenttor
Fred Grimes

Your post is so interesting. and it is more useful and helpful for me. Thanks for share this valuable post.

commmenttor
Ershadul Hoque

I am using lettuce.django app to follow BDD which is itself a TDD. and I like the specification by example pattern.

commmenttor
ifoo 13th Aug., 2012

Continuing from jlennon's recommendations one can use the built-in map() function to further reduce the amount of code:

def greater(self, val1, val2):
if isinstance(val1, basestring) or isinstance(val2, basestring):
return sum(map(ord, val1)) > sum(map(ord, val2))
else:
...

The "basestring" type is used to cover both string- and unicode-types.

commmenttor
Post a comment Name :

Email :

Your site url:

Comment :

© Agiliq, 2009-2012