Some Unit Testing Remarks

by Charles Miller on January 18, 2004

Every bottle of James Squire Original Amber Ale has a little story about the beer printed on the label. This one is all about how often the original James Squire got laid. I suppose it's fitting: maybe someone will be inspired by label and beer, and use it as an excuse to wake up the next morning and wonder how the hell they got drunk enough for that to look attractive (a question generally shared by the other party). However, its slightly less appropriate to me, having spent this Sunday night in my apartment with a six-pack of the aforementioned, and the X-Box.

Which is an interesting contrast to spending Friday night being rained on in an open-air cinema, watching Grease. I have this theory that every member of my generation (being, as I am, on the fading edge of Generation X, but not quite into the rise of Generation Y) knows this movie off by heart, whether they want to or not.

I didn't join in the singing. Although if I'd had more beer then instead of now, I probably would have.

Anyway, on with the Unit-testing stuff.

Hani on TDD

I don't write my tests first. I know very few people who do. It's awkward, fragile and unintuitive. For those who enjoy it and find that it's none of those things, great! At best, I'll do a mixture of the two, and have something vaguely functional, then write a testcase and make sure it tests all the conditions I'd like it to pass under even though I know that it'll fail.

I like to write my tests first, often to the point of writing the test, and then using the IDE shortcuts to create the classes and methods I'm testing. Not writing tests first is generally a sign I'm getting lazy or complacent. I find that writing a test first focuses my mind on the precise problem I'm trying to solve, and gives me a nice indication of when I've solved it. In a way, it keeps my honest.

I also like the feeling of certainty. You write something that deliberately doesn't work. You make it work. You are certain that the state of your code has changed. If you write a test that works, change some code and the test still works, have you really done anything?

Worse, if you have some code, and then write a test against it that works, are you sure the test is really testing what you want it to?

I also find that the need for code to be testable colours the way I do design. I'd much rather write code that is easily testable, because then I spend less time writing (and running) tests. Experience has taught me that as soon as you have tests that rely on the container being up to run, you're quite likely to slow down by an order of magnitude. So I try to avoid writing tests that involve a container.

I wouldn't, however, say I do test-driven design. Tests are one of the factors that influence my design, but they certainly aren't some overwhelming force that drives everything else.

Richard Saunders on Unit-testing Tool Boy

Tool Boy (TB) gave me a rant about unit tests saving time. I asked the sorry sod, "if they save so much time then how come you're so late on all of your work?" He talked all about the bugs that the unit tests would find... The truth is that we're not held accountable for that too much. There are always too many parts, so its never clear why the system is unstable... Get your stuff done and shut up about your ficticious unit tests. Time to deployment is job #1, cost is #2, quality is for people not working in IT.

This is what finally convinced me that Saunders is indeed satire. Quality is cost, is time to deployment. I've seen attempts to separate them, and they've all ended in tears.

Dave

As requirements complexity increases, test case code becomes a duplicate of the code being tested

This is the big testing danger-sign to watch out for, as I mentioned in a previous rant about mock objects. It's the reason I continue to fight a rear-guard action against the direct testing of private methods. Tests should be stimulus-response. I poke the object this way, it gives me back this result. I poke the object this other way, and the resulting state of the application model is this. Moving in so close that you're testing each individual neural pulse, rather than the aggregate response, leads to tests that are either meaningless, unmaintainable, or both.

Previously: The Importance of Response-Codes

Next: Confluence Beta 2... er... 3