A little anecdote. I'm slowly trying to get my team to wrap their heads around the idea that any new feature must be accompanied by unit tests as we near the point where they are absolutely required to write unit tests before they write code and the tests become part of the deliverable. One thing I know is that if you haven't written a lot of unit tests yet, you don't really understand the value of them except very much in the abstract, so I am also trying to point out the value to him as we go.
One of my developers is writing a function that uses the compiler module to inspect some Python code, it's not really important why. He had just learned how to write some unit tests in Javascript and I was teaching him how to use the stdlib unittest module for his unit tests written in Python. His implementation isn't written yet, he is just starting to figure out what the interfaces look like, which is a great time to start writing failing tests.
I told him, start with this:
import unittest
class MyTestCase(unittest.TestCase):
def test_myParseFunction(self):
assert 0
.. and run that test, which he did, and it failed, and I said "good". I started pointing out to him ways he could make very minor modifications to his code to make it easier to test (not nearly enough has been written on the subject of making code easier to test, BTW--bloggers, get on it!).
One of the improvements I asked him to make was to move some functions into another, more relevant module than the one he was working in. He did that, then wrote version two of the unit test:
import unittest
import mynewmodule
class MyTestCase(unittest.TestCase):
def test_myParseFunction(self):
self.assertEqual(mynewmodule.myParseFunction("(python.code)"), [expected, output, structure])
Now, remember that he hasn't implemented myParseFunction yet. So I asked him to run his failing test one more time. And, a surprise to both of us, we got this:
[ERROR]: test_mymodule.MyTestCase.test_myParseFunction
Traceback (most recent call last):
File "/usr/lib/python2.5/unittest.py", line 260, in run
testMethod()
File ".../test_mymodule.py", line 7, in test_myParseFunction
self.assertEqual(mynewmodule.myParseFunction("(python.code)"), [expected, output, structure])
File ".../mynewmodule.py", line 19, in myParseFunction
return compiler.parse(s)
exceptions.NameError: global name 'compiler' is not defined
What the.. oh right! He imported compiler in the original module, but forgot to move it to the new module. The unit test - so far, one line long and expected to fail in a relatively uninteresting way, had already found a bug. My favorite part was that it happened this way to someone learning why we put so much value on unit tests.