The automated testing confessional
Hi, my name is Evan. And I don’t always start a new app by writing tests.
There, I said it! Crazy, right? Well, ok, maybe within our test-obsessed Ruby world.
As much as I promote automated testing and Test Driven Development, and you can call me a hypocrite, but I don’t always TDD or even test first. Sometimes I just want to write some %#@&ing code!
But here’s the catch: it almost always bites me in the ass later.
Take for example Ruby Pair. Ruby Pair is, currently, a humble little directory of people interested in pairing on Ruby, remotely or in-person, for fun or to work on open source.
Bad Evan! You only started writing tests a few weeks in!
Now that I’ve berated myself…
Ruby Pair hasn’t been my full time job; it’s been my hobby project for the past 3 weeks. When I’m working on a project for fun, or on my own dime, I’m more likely to try to see how far I can get without automated tests.
Why? Because I’m lazy, dammit!
The key is to be lazy in a good way.
So I have another confession: until I found Ruby, Perl was my favorite tool to avoid writing shell scripts. I deplore writing shell scripts. Sure, I live in the shell (zsh, thank you very much) on a daily basis but that doesn’t mean that I have to code for the shell using the shell!
Larry Wall, the author of Perl, talks about the “three great virtus of a programmer”. He lists laziness chiefly among them. When Larry says “laziness”, he means the kind of lazy where you’ll go to great lengths to avoid doing unecessary work later.
Sounds a little like automated testing, if you think about it.
When writing a new app, at first, it’s almost always easier for me to begin by just banging out code. How many times have you set up authentication in an application? Or created a User class or a users table? Pretty motherhood and apple pie, right?
So you’re writing your code, you think everything’s fine, everything’s good. Then the next thing you know, you’re on fire!
Ahem Ok, I mean “you discover that your code base is a flying spaghetti monster”.
My point is twofold:
You don’t miss something until it’s no longer there. It is important and reasonable to sometimes avoid writing automated tests. Now don’t go and use that as an excuse to your momma if you get busted for it. Occasionally skipping your automated tests is a healthy way to develop an appreciation for them.
Not every piece of code should necessarily be tested.
Well, not really…
Have you ever tested every path in your application? If you say “yes” then that application must have been no larger than a few methods.
Instead, we pick and choose what to test. We do it all of the time.
Typically, most of us write tests for the happy path. “What’s the happy path?”, I’m occasionally asked. It’s that magical case when all of your inputs are valid, all of your external dependencies are met, and so everything works as expected. Everything else is a “sad path” a.k.a. “degenerate” or “edge” case.
“What not to test” is a heuristic that varies from project to project. Personally, I decide what not to test based on the (1) risk and (2) impact of failure of the particular component/feature.
A couple of anncecdotal examples:
- ALMOST ALWAYS TEST: Whenever I’m dealing with currencies, virtual or otherwise, I’m writing a test. Few things tick off a user faster than mishandling their money!
- RARELY TEST: Authentication? Psh! I’ve set up Devise enough times. For the happy path, it’s easy!
If you’re not familiar with the basic ideas behind risk management (and you’re too lazy to follow that Wikipedia link), use this rule of thumb: just how confident are you that your code will work? How bad will it be if it doesn’t? Listen to your Jiminy Cricket.
To sum up: not TDDing or writing your tests first is a decision. If you’re going to make that decision, do it in an informed way. Occasionally, writing code without tests serves as a useful touchstone to remind us why we write tests and use TDD.
Posted by evan on Sunday, September 04, 2011blog comments powered by Disqus