A lot of people try Test Driven Development by writing the test, writing the code, and then wondering what the big deal is. Here’s the process I follow along with an explanation of why each step helps.
As a quick note, all tests are written with the RSpec framework.
1. Write the test
Let’s say that I need to import a csv file containing a list of zip codes into a table on my Ruby on Rails application. I’m going to ignore the UI or view for uploading the file for right now and concentrate on the logic that opens the file and imports the zip codes. I’ve decided that I want this functionality on my ZipCode model. So, I open up my RSpec specification for ZipCode’s and add the test.
vim spec/models/zip_codes_spec.rb
Here’s the test. This assumes a file with 100 new zip codes.
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe ZipCode do
it "should import the zip codes from a file" do
count = ZipCode.count
ZipCode.import_from_csv(File.dirname(__FILE__) + '/../fixtures/zips.csv')
ZipCode.count.should == count + 100
end
end
2. Outline the method using comments.
Here’s a quick example, then I’ll explain why I do this.
class ZipCode
def self.import_from_csv(filename)
# open csv file
# take each row and ...
# create a new zip code from it
# close csv file
end
end
The primary thing I get from this is that I can see what the code will look like and I can determine which parts of my code I need to break out into new methods. Of course, new methods get their own tests, hence step 3.
3. Write tests for any supporting methods
In this case, I’m probably going to use the Fastercsv library for Ruby, but for the sake of argument, let’s say I have to write my own method to create a ZipCode from a row from my CSV file.
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe ZipCode do
it "should import the zip codes from a file" do
count = ZipCode.count
ZipCode.import_from_csv(File.dirname(__FILE__) + '/../fixtures/zips.csv')
ZipCode.count.should == count + 100
end
it "should create a new zip code from a row of a csv file" do
row = ['84043', 'Lehi', 'UT']
ZipCode.create_from_csv_row(row)
ZipCode.find_by_zip_and_city_and_state("84043", "Lehi", "UT").should_not be_nil
end
end
4. Run the test.
Running the test does one important thing for you. It insures that there isn’t some unexpected behavior in your code that gives you a false positive. Once you see each of your tests fail, you’re ready to go.
5. Write the code.
For me this is the best part of the challenge. I love writing code. Tests are just the insurance for me that I’m writing good code. As before stated, I’m going to write this using the Fastercsv Ruby library.
class ZipCode
def self.import_from_csv(filename)
# open csv file
# take each row and ...
FasterCSV.foreach(filename) do |row|
# create a new zip code from it
create_from_csv_row(row)
end
# close csv file
end
def self.create_from_csv_row(row)
create(:zip => row[0], :city => row[1], :state => row[2])
end
end
6. Refactor if necessary
The 6th step is one that is frequently, but not always used. Sometimes we write messy code to get the job done. That’s really much more acceptable with Test Driven Development because once we get the test to pass, we can go back and change the code. The test tells us if we’ve broken something while refactoring and we’ll know when our pretty code actually works.




