From: Jim Weirich Date: 2003-06-02T21:08:25+09:00 Subject: Re: How to structure a program for unit testing On Mon, 2003-06-02 at 07:24, John Johnson wrote: > The time has come. I'm tired of that unsure feeling when I'm about to > release a program. So I've decided to jump on the unit testing band-wagon. > Trouble is, the wagon is going a little fast for me, and I'm kinda' hanging > off the back end of it. The best way to learn about unit testing is to ... do unit testing. Your first attempts will feel awkard, but you will improve with time. There are several ways to approach unit tests. You didn't mention a particular technique, but I would recommend the "test-first" approach where you write your unit test before the production code. If you follow the rule that you never add new functionality to a program without a broken unit test, and then only write enough code to make the test pass, then you get excellent test coverage with a small investment of time (that pays for itself many times over). If you are not familiar with the "test-first" approach, there are a number of writeups on any of the web sites devoted to XP (Extreme Programming). Now, on to specific questions... [... John's programs tend to be file massagers in a single source file ...] > Is it possible to devise unit tests for programs structured like this? Yes! > Should I break my program into more source files? Not neccessarily. I would put the unit tests in their own file however. > Should I have a lot of smaller functions that do what the large function > does? [...] This will come out of your unit tests. If the code is hard to test, you will eventually learn to write it in chunks that are easier to test. > When doing tests on file massagers, do you have a set of input files that > you use for the tests, and that remain with the tests, ie. TC_Massager would > use tc_label.txt and tc_format.txt? I try not to depend on external resources for *unit* tests. If the file can be processed a line at a time, I will unit test a line oriented function. If single line processing doesn't make sense, then I construct small input files in the test and pass them to the function under test. StringIO is really helpful here. Here's a quick example. Suppose I was writing a program to add -style HTML tags to keywords in a Ruby program. A small test example might look like this ... require 'test/unit' require 'stringio' class TestFormat < Test::Unit::TestCase def test_func input = <<-EOS def run puts "HI" end EOS out = StringIO.new format(StringIO.new(input), out) assert_match /def<\/b>/, out.string assert_match /end<\/b>/, out.string end end Hope this helps. -- -- Jim Weirich jweirich@one.net http://jimweirich.umlcoop.net --------------------------------------------------------------------- "Beware of bugs in the above code; I have only proved it correct, not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)