I was talking with someone recently about unit testing. His dilemma boiled down to the idea that he knew unit testing was one of those mythical “Good Things” but he couldn’t bring himself to do it; it seemed like such a large commitment in time. I’ve been thinking more and more about this, and I have come to the conclusion that the time factor in unit testing is actually a myth. Here’s why I think so.
Do you write code, and declare it finished when you are done editing it? I hope not. No, you go to your application and test the page you just changed through your browser. If you’re working on a CFC, maybe you go to a page named test.cfm, on which you have a few CFC calls and a CFDump. You then looked to see if the results you got conform to the results you expected. Did you do that? Then you just unit tested! The only difference between that and a formal unit test is that you throw away the test after you were done writing that piece of code.
I propose you formally unit test instead. Instead of throwing away that test code, put it in a formal testing framework. You’ll probably have to change it a bit to get it to work with one of those frameworks, but the learning cost for doing it this way is much, much cheaper that TDD. Once you do that, you’ll never have to worry about breaking code again because you hold on to every test you’ve ever written. Well, okay, you’ll still worry, but you know as soon as you do it what code you’ve broken, which is a much better place to be at.
I think a big part of the underlying misconception comes from the fact that most discussions of unit testing include a description of Test-Driven Development (TDD). That is the system were you figure out how exactly your code should behave, write tests to check for that behavior, then write code that behaves in a way to pass all of your tests. That is going to change the amount of time you spend on development (at least up front, where we tend to myopically be focused.) More than just a hit in terms of development time, it’s a hit when it comes to spending the time learning it. Mind you, I’m not saying that TDD is bad; it’s just a paradigm shift, and a big one at that.
BUT that doesn’t mean that unit testing IS Test-Driven Development; TDD relies on unit tests, not the other way around. Go ahead, write your unit tests after the fact. No one will know. In fact, many unit tests get written in response to bugs, even when you are doing TDD.
Another misconception is that you have to test everything you do. Some things work better with formal unit testing than others. Yes, with mock objects and development databases you can unit test anything, but that makes the learning curve even steeper. Screw that; don’t make it harder for yourself. Small components with a limited range of functions are the easiest to start to work with. Examples usually include some sort of calculator, or other such item that I never use in actual code. So here are my recommendations for low hanging unit testing fruit.
- Authentication code, specifically that which test usernames and passwords (as opposed to session management)
- Utility code, like a phone number formatter, or custom date converter
- Parsing code, like code that takes a custom XML format and converts it to a usable format
- Problematic code, code that breaks every time you do an update.
So start moving your informal tests to a formal unit tester. Start with the small stuff and don’t worry about testing everything. And for god’s sake don’t think you have to reach for TDD to be successful with unit testing. Somewhere between where you are and where you are heading is a much better place.
In case you want to know more about unit testing and ColdFusion, check out the ColdFusion unit testing frameworks:
Update: Someone pointed out to me that I had misspelled “TDD” as “TTD.” Sorry. I’m dumb sometimes.