You are here

Practicing TDD

I have been rereading Thomas Limoncelli's Time Management for System Administrators. One of the points Limoncelli makes is: "[P]sychologists tell us that it takes 21 days of doing a new behavior to develop it into a habit." Give or take a few days, of course.

Test-driven development (TDD) is something I keep revisiting. I have Kent Beck's book on the subject and have read it at least twice. I have tried doing TDD on at least four separate occasions but I seem to stop usually a few hours or a day into the process.

Mark Mzyk wrote of having similar issues with TDD. I disagree with his statement that the issue with TDD is a lack of experience. Instead, I think it has to do with a lack of practice. If you don't do it consistently for any length of time, say three weeks, you're not going to adhere to it. If you follow it, even if not deliberately, you eventually find yourself, as Peter Harkins put it, "drifting into test-driven development."

I think it's kind of like learning to touch-type properly. It's painful and difficult and slow now because I lack experience. As I said before, I spend time actively thinking about which finger should be used to press which key. However, even just a few days into it, I find I spend less time thinking about it.

"How can I practice TDD?" I ask myself. Well, my big thing recently has been problems from Project Euler. I can use it there!

Most of the problems from Project Euler provide a sample test case. For example, problem 1 states:

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.

Find the sum of all the multiples of 3 or 5 below 1000.

From this, I know that we are solving for the sum of all multiples of 3 or 5 below 1000. We also know that the sum of all such multiples below 10 is 23. This means that I can set up a test script:

  1. require 'test/unit'
  2. require 'euler1'
  3.  
  4. class TestEuler1 << Test::Unit::TestCase
  5.   def test_euler1
  6.     assert_equal( 23, euler1( 10 ) )
  7.   end
  8. end

Running it complains that it can't find a file for euler1. After touching euler1.rb, it complains that there is no method euler1. And after each new error, more changes are made until, eventually, euler1.rb looks like:

  1. def euler1( n )
  2.   23
  3. end

and the test passes. This obviously won't answer the question correctly but doing this proves that the unit testing framework works. It also proves that it considers 23 to be equal to 23 which indicates that there are no silly math errors in the language interpreter, at least at this point. From here, I know I can implement an algorithm and as long as it meets the given criteria, the test should pass. If I'm uncertain about this, I can find other points to test as well. The values for any given n up to 58 are listed in sequence A126592 at The On-Line Encyclopedia of Integer Sequences.

Since this process appears to work for one problem, it should work for all of them. I'll try it and see how it goes.

Topics: 

Add new comment