Yes, Even Shell Scripts
I write a goodly number of shell scripts because, well, you can do a lot of automation with a low-tech shell script. So I have enough of these buggers now that I can't remember if they all work. In other words, I have more than two scripts. And I feel this twinge of fear every time I tweak one of them.
For example, just the other day I was fiddling with a script that
tallies up the number of words in a file. The proper way to do that
on Unix is with a wc -w command. The -w
part is really, super important because that means "words".
And this script was working great, until I tried to make it better.
Somewhere in the making-it-better process I changed the
-w to a -l. This means to count lines, not
words. It turns out that makes a difference.
Darned if I know why I wanted to count lines at that moment, but I suspect it was a debugging aid of some sort. Trouble is, I left that change in there after the debugging frenzy. So for days on end the script happily produced a number. Unfortunately, it was the wrong number. And finally I noticed that this number wasn't increasing at the rate I expected. OK, so a problem like this only takes a few seconds to fix, but that's after I've realized that there is a problem.
Sigh. Yours truly forgot about his friend the self-checking
test. So when Jim Weirich blogged about the Ruby Session module, I was all over it.
Here's a test case that screams if I inadvertently change
-w to -l again:
#!/usr/bin/env ruby
require 'test/unit'
require 'session'
class ScriptTests < Test::Unit::TestCase
def test_countwords
bash = Session::Bash.new
out, err = bash.execute "./countwords.sh tenwords.txt"
assert_equal 0, bash.exit_status
assert_equal "", err
assert_equal "10", out.chomp
end
def test_build
bash = Session::Bash.new
out, err = bash.execute "./build.sh compile"
assert_equal 0, bash.exit_status
assert_equal "", err
assert out =~ /BUILD SUCCESSFUL/
end
end
That second test there checks my build script. See, the build script uses Ant and once in a while I insert my own brand of XML in the Ant build file. And XML parsers haven't figure out my brand yet. So that test checks that the build file gets parsed without error and that it actually runs the Ant target successfully.
So yes, even shell scripts want to be tested. Take my (ahem) word for it. Better yet, scripts can be tested with this handy Ruby module. And if I can test a script after it seems to be working, then why wouldn't I want to eat the dessert first?