One suggestion was to not bother writing tests, because my example
script has little logic to it and is short enough to throw away and
rewrite if it’s wrong. For this particular script, that’s probably
true. But this is part of a bigger library, and the example I posted
was intended to be simple enough to discuss the principles without
getting bogged down in details.
Another response pointed me to a talk by David Copeland at GoGaRuCo
2011:
Test-drive the development of your command-line applications.
This is a good talk, and worth watching. It definitely helped, but
still didn’t deal with some of the issues in my example problem, like
how to test the copying of files to a remote server or running
commands on a remote server.
Another response pointed me to David Copeland’s book,
Build Awesome Command-Line Applications in Ruby.
I had just ordered that book a few days earlier, and it’s now in my
reading queue. I expect to learn quite a bit from it.
Here’s my original solution to the example problem. It has the
redeeming quality of working for its intended purpose, but I’m not
totally happy with the tests.
I split the problem into two parts: building the package, and
uploading the package. I made little classes, essentially
MethodObjects, for each part.
First, the package building part:
As you can see, I’m not actually testing the effects of the various
commands; instead, I’m just testing that the commands look right. Not
ideal, but better than nothing. I’m testing the commands by mocking
the backtick method on the object under test. I realize that mocking
a method on the class under test is a smell, but it seemed better than
the alternatives.
Here’s the code to make it pass:
Here’s the tests for the package upload part:
Note that I don’t test the commands that I’m executing in the remote
SSH session, because I couldn’t think of a good way to do that at the
time I wrote this.
Here’s the code:
To use these classes:
And there’s my less-than-ideal solution to the problem. Now that
you’ve seen the code, how would you improve it?