Test Driven Development: First Impressions
Thanks to Noel Llopis' great series of articles, I'm sold on test driven development. I'd like to spend a little time recording my first impressions -- after only one week of experience. For maximum benefit, I recommend reading Noel's articles before or after continuing.
Disclaimer: the product I'm working on, a programming language and its compiler, is particularly amenable to test driven development it's very straightforward to see whether the code is doing the right thing or not. It's less obvious how to apply test-driven development to some other areas, specifically user interface design and computer graphics. Now let's get to my observations.
First, test-driven development is fast. You would think that having to right twice as much code, maybe more, would mean that TDD is slow. But this doesn't take into account the fact that you're debugging time is reduced to almost nothing, and the act of writing tests is nearly equivalent to designing software on paper or in your head. You don't have to worry about writing good, or even correct, code, as long as the tests pass. For example, my compiler only supports two operators right now. In even those are hacked for specific data types. But that's okay, because in test-driven development there is a mantra: untested code doesn't work. It's just like in the field of security: unproven code is insecure. If you want to see the other myriad advantages of having tests for every piece of your code, there's plenty of literature out there.
Second, test-driven development is fun. The "find insufficiency" - "write test" - "see it fail" - "change code" - "repeat until it passes" iteration cycle is extremely rapid. And after every change, you get to see all the other tests pass, so you know you didn't break anything. Instant gratification. It's like a drug. I got more done last night than I have in some weeks, just because I couldn't stop. TestInfected for sure.
Third, test-driven development breeds good code. The logic here is pretty simple: your code needs to be easy to test, so your objects become easy to instantiate and easy to use. Noel elaborates on this.
I'm not sure I can back this up, but in order to effectively practice TDD, I highly recommind using a good build system. Visual Studio might not cut it. I'm using SCons and I find that I almost never do a build without running the tests (typing "scons test") as well. However! This may not be a limitation of TDD, since having a good build system is a good thing anyway. ;)
Now for some details about my particular setup. As I mentioned, I'm using one of SCons' newer features, the ability to associate actions with Alias nodes. How to do this. I'm using Boost Test and some Python scripts. I have a thin wrapper around Boost Test to make it a little easier to read. (#define TEST BOOST_AUTO_UNIT_TEST and such.) I'm not sure I know how to follow Noel's rule of "one check per test" yet. Most of my tests depend on values created in previous tests. For the same reason, I'm not sure how to effectively use fixtures yet, since I want to test the fixture setup and teardown too.
p.s. I used Dragon NaturallySpeaking to write this, so if you see any weird words or grammar, please forgive. I tried my best to correct what I can see.
You should mp3 the speeches behind audioblogging entries!
...I'll read the rest of this all again when my brain is more worky.
what speeches?
Can you not record your voice whilst speaking to the computer?
Told you so. :D
The advantages of TDD become exascerbated even further in interpreted languages because you can skip the build phase.
Hm, maybe. Not sure. Why do you want to hear it?
I was considering doing it myself, actually. Vanity loves company.
Ah. I'm not hip to this whole audioblogging thing. I'd rather read than listen to people talk.
Eh. I just need speech practice and figured that this may be a good venue for such.
Listening to me blabber and correct myself is "speech practice"? I'm confused.
Glad you're infected!
You should use fixture-less tests to determine if the features you're using in later fixtures work, then assume they work.
TEST(CanLoadFromFile) { ... }
class TextFileLoadedFixture { TextFileLoadedFixture() { // Do you loading and assume it all works, no need to test results } };
TESTF(TextFileLoadedFixture, CanReadByteFromFile) { byte result = file.ReadByte(dest); CHECKEQUAL('a', result); }