Tue, 25 Feb 2003
I did another test-first demo, this time in Ralph Johnson's software engineering course. I'm chagrined to say that in a 1.5 hour class, I ended up producing only this code in two test-then-code iterations:
def move(seconds, from_id, to_id) shorten(from_id, seconds) shorten(to_id, -seconds) [records.record_with_id(from_id), records.record_with_id(to_id)] end
We were just starting to get into the swing of things when I looked at the clock and saw I had five minutes to go. Argh!
Part of the slowness was due to popping up for meta-discussions about test-first (and, I confess, digressions like the implications of test-first for the choice between statically and dynamically typed languages), and part of it is that I had to explain the application under test. But, as I was writing this note, I found myself chastising myself for not being dutiful enough about refactoring common test code.
You see, the
first_record = @session.add_record(FinishedRecord.new(first_time, 1.hour, first_job)) # do the move, check the results.But to do that, my test had to create (and I had to explain) a
So, I found myself telling myself, I should have long since
factored out an
But wait... it's common for me to test new internal methods through the command-line interface. If I'd done that, my test would have looked like this:
job 'first job' job 'second job' add_record '12:45 pm', 1.hour, 'first job' add_record '1 pm', 2.hours, 'second job' # do the move and check the results. ...(Because my command line is Ruby, I can use the same unit testing tools as I do when testing internal objects.)
In other words, the command line 'move' is almost the
easy-to-use-and-explain utility method I berated myself for not having
written. It just lives at a different
layer, one with a pretty straightforward translation to
I deviated from my common practice because I didn't want to have to explain the tradeoffs between testing methods directly and testing them indirectly. I wanted to launch into showing students some tests. Instead, I found myself explaining too much and slowing myself down.
I don't want to make any general claims for this technique. But for this application and this person, the command line serves as a handy collection of test utilities. Because the command line is Ruby, I can also "dive beneath the surface" and call methods directly when I need to.
I love command lines.