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
<b>-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 /<b>def<\/b>/, out.string
      assert_match /<b>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)