- Introduction
- Test-Driven Development
- Incremental Test-Driven Development
- The Payoff for Test-Driven Development
- Learning to Write Good Unit Tests
Learning to Write Good Unit Tests
Like a good many things, we can learn to get good at writing unit tests by reading the unit tests that other people have written. A great place to start is Nathaniel Talbott's Test::Unit web site, which contains the online documentation for Test::Unit. You can also download the complete Test::Unit package from there so you can see the unit tests that drove the development of Test::Unit.
NOTE
Developers with a background in Java might also want to check out the JUnit site, which is the site for the Java version of the Unit Testing framework. It contains many interesting articles and experience reports of Extreme Programming style test-driven development in Java.
When learning to write good unit tests, the thing to remember is that unit testing is intended to validate that a class and its methods do what the developer intended them to do. Unit tests are not intended to replace functional or acceptance testing; rather, they ensure that the code we release to functional testing is better than it would be without our unit tests. With that in mind, at first what matters is that you start to write the unit tests first. Once you've started writing the tests, you'll quickly learn what extra tests you need to write.
You know that you need to write extra assertions in your unit tests when mistakes slip through your unit test suite to cause grief later. Whenever that happens, rather than starting the debugger, or running the code interactively in an irb session [ref "Ruby for the Nuby" article], write more assertions into your test cases. One or more of these assertions will give you enough "pertinent information" to enable you to localize the mistake.
Unit tests can be applied to any class, even those that use lots of other objects. The two Ruby scripts below are the start of the test suite that was used to create the Odometer example from the last article. The first script replaces the OdometerTest.rb from last time, which showed how to test the Odometer using irb, but this format is so much easier as it avoids the need to manually check the printed output. The second script is just an easier way to run all of the test cases with a single command line.
# tc_Odometer.rb require 'test/unit' require "CircularCounter.rb" require "OdometerWheel.rb" require 'Odometer.rb' class TC_Odometer < Test::Unit::TestCase def set_up @odo = Odometer.new(6,10) @bin = Odometer.new(8,2) end def test_increment 12345.times { @odo.increment } assert_equal("012345", @odo.reading, "Wrong reading") 32.times {@bin.increment} assert_equal("00100000", @bin.reading, "Wrong reading") end def tear_down @odo = nil end end
# ts_OdometerProject.rb require "tc_Odometer.rb" require "tc_CircularCounter.rb"
So start practicing test-driven development by adding more assertions to this test suite and then adding whatever functionality you desire to the Odometer. When you feel comfortable with that, start practicing with your own projects.
NOTE
Although there are several books on Ruby, my personal favorite is still Programming Ruby: The Pragmatic Programmer's Guide (Addison-Wesley, 2000, 0-201-71089-7) by the The Pragmatic Programmers, Andy Hunt and Dave Thomas. The first place to visit though is the main Ruby site, because that's where you can find the places to download Ruby, as well as a wealth of articles and tips about using Ruby.
All of this sample code was tested with a fresh download of Ruby version 1.6.6.