6 Reasons to develop your tests first

I get frustrated a lot with the software I write. Typically, it starts to get so complex that any small, local change could potentially effect some other part of the code. And it gets so complex and unmanageable that I usually start fantasizing about rewriting it. But there’s something I’ve learned the hard way. Writing your tests first can really help remove the stress of a complex piece of software. Test Driven Development (TDD). It’s not the panacea that the hype and buzzword mongers want you to believe, but as a discipline it does relieve some issues when developing large systems.
One of the mainstays of Test Driven Development is to develop your tests first, before you write the code that the test will check. I would like to share with you some of the advantages that the discipline of TDD can impart on your code.
1. Prevent imagination overrun
As a programmer, I love tinkering with code. I love to experiment with some new way to structure my objects, or a different dispatch strategy, or any number of things. It makes me feel clever to come up with a solution that can deal with way more cases than just the few I know I need now. But all too often, those meandering experiments waste time. Usually, ten simple lines of code will do precisely what I want, and I let my imagination run wild with Rube Goldberg algorithms.

[edit: I changed the graphic to be more clear. See the original graphic.]
When you write your test first, you know exactly what your software needs to do. You write a test and watch it fail. Then you write the simplest code that makes the test pass. And that’s key, you make the simplest change to the code that makes it pass. Not the most ingenious, not the most modular, not the most general. All those things just mean complex. The discipline of writing the simplest code possible and nothing more will help you save time.
2. Know when you’re done
Related to preventing imagination overrun is knowing when to stop writing code. Let’s face it: even each class can suffer from feature creep. You want to make it handle the more general case. Or someone thinks you should use the Observer Pattern. These kinds of feature creep are just a waste of time.

Most software systems I’ve worked on required so much work that you really did need to know when to stop work on one piece and move on to something more important. A test defines when a feature is “good enough”. The discipline has a built-in check for completion. If you pass all of your tests and there are no more tests to write, it works well enough. So why waste your time on it when there’s more important things you could be doing? If you stop coding when your tests pass, you will use your time more effectively.
3. Catch regressions early
Code starts to get complex after you’ve been working on it. And especially after you’ve not worked on it for a few weeks. When you start to make changes to the code, how do you know you haven’t broken something? Maybe you can keep it all in your head. But maybe you can’t. No body can keep it all in their head. So maybe you do a few manual tests to try it out. But then you make some more changes, and you start to wonder again: “Did this break something.”
And eventually, your test reveals that somewhere in the 300 lines of code you’ve written or modified you introduced a bug. But where was it? When was the last time you ran your tedious manual tests?
When you develop your automated tests first, you know that pretty much anything important that needs to happen in your program will happen, or if it doesn’t, at least it will tell you. And your tests are so easy to run (usually a button press or an expression entered at the REPL) that you do them repeatedly. Hopefully after every tiny, atomic change. That way, you can know which change breaks the tests and fix it. Developing the discipline to run your tests often, almost compulsively, will save countless hours of frustratedly hunting down bugs.
4. Create more modular code
When I do Test Drive Development, I’m often surprised by how clean the design turns out to be. I’ll often see what are referred to as standard design patterns emerge, fully formed, completely unintentionally. I like to think of that as evidence of the hidden power of this discipline: that in testing the interface of a module (Unit testing) you are forcing the interface to be well designed.
Instead of asking yourself what should this module be able to do, the Unit test forces you to ask “how will I or other code use this” though in an indirect way. It is akin to a product designer creating something to be used by people. He/she asks what the user will need to do to the object (push a button, turn a knob), how to let the user know how to do that (making the button and knob highly visible, perhaps textured), and how to let the user know what the effect of the action is (beeping or changing the volume).

Right! It works the same for a software module. When writing the unit test, you ask “what will do I do to the object?” (what you are testing), “what function do I call?” (the interface), and finally the essence of the test: “how do I know it did what it should?”. Writing good unit tests will help you design better software.
5. Cleaner code
Have you ever wanted to reorganize some code, maybe break larger functions down into smaller ones? Move some methods to another class? But then you thought twice about it because you were afraid to break the code. When I don’t write tests I sure do. But when I have lots of tests, I usually feel pretty safe. Those corner cases are covered by the tests, so if I break something, I can always find it. Refactoring my code is actually fun, because I’m not afraid of breaking anything.
Also, since I write the simplest possible thing to make the test pass, my code is usually pretty neat anyway. So there’s less housework to do.
6. Satisfaction
And writing code can be such a chore when you’re facing the task of writing a gigantic system. Breaking your development down into small bits, each with a defined goal, makes the whole process much more pleasant. You get a little reward after each iteration (seeing all you tests pass) and you are never daunted by the apparently treacherous path to the end of the project. It lets your mind concentrate on the current step in the process instead of worrying about the big picture. Writing tests first gives you peace of mind.
Popularity: 100% [?]
Filed under Programming Practices |28 Responses to “6 Reasons to develop your tests first”
Leave a Reply

Thanks for that. People always tell me these things but never with pretty pictures…
[…] Write your tests first When you develop your automated tests first, you know that pretty much anything important that needs to happen in your program will happen, or if it doesn’t, at least it will tell you. […]
Excellent. I didn’t read any of it… only looked at the pictures and the reason “titles”, and it all makes perfect sense already.
I’m adding this blog to my RSS
[…] I’ve always been a fan of TDD, and spoken often about it. In doing some research recently, came across an excellent article on LispCast that covers 6 Reasons to Develop your Tests First: […]
Love it - blogged it - http://rationaltester.wordpress.com/2008/01/11/test-driven-development-tdd/
Wish more people would think this way!
Nice. I also recently discovered TDD. It is a joy
How do you know you test code is bug-free?
Remember, in order to be doing it right, your tests ought to be failing when you first write them. If you write a test and haven’t ever seen it fail, who’s to say that it will?
Simple is always good. So is getting the minimal done that does the job anyway. Makes it so much easier in debugging later on if that need arises.
In my (limited) experience, Test Driven Development is seen as good but there’s never much enthusiasm to adopt it. It’s seen as unnecessary hassle when you have deadlines to hit, we always seem to end up either just doing acceptance tests at the end or doing periods of development exclusive to updating our tests to match the new code.
But as I’ve been working on these stages of development something occured to me. Even if you test-driven development can’t guarantee your code is bug free (your tests can always be inadequate, nobody is perfect) what it can guarantee is that your code is actually testable. I’ve spent days working on writing tests for a single class, trying to figure out how to actually write a test for it.
If you don’t write your code with the intention of making it pass a test you are almost certain to end up at the point where writing those tests is overwhelmingly complicated. You’ll end up with 100 line methods with crazy amounts of branching and other testing nightmares.
You probably should have as many lines of unit tests as actual programming.
I recently completely refactored a set of model classes (4 classes with 45 tests between them) and since functionality was not expected to change, the tests were a perfect crutch. I did write these tests after I wrote the original model code as I had not chosen how to test. Right now, I am developing a set of views and I am writing the tests for the views first since the testing frameworks have caught up with me!
I release you from my rant. Good post.
One minor clarification.
You say:
“you write the simplest code that makes the test pass”
Actually what you do is create the simplest *solution* that will make your test pass. Sometimes the simplest code is a chack, and refactoring to produce the simplest overall solution means refactoring (which you do talk about).
The point is to not just always be writing the simplest next step, but to create the simplest overall solution - which can sometimes be more owrk. This is evolutionary architecture at work.
At Resolver Systems we practise TDD (along with pair programming, continuous integration, iterative development and other XP classes).
We have a ratio of about three lines of test code per line of production code. This kind of ratio is pretty normal in TDD shops…
Have you read the Nov/Dec issues of Better Software Magazine - a good article with some traps and pitfalls of TDD.
Also mentioned in http://www.artima.com/weblogs/viewpost.jsp?thread=216434
I agree with some of Jim Coplien’s points, but still find TDD worth while.
I was working for a group that was saying “TDD” would make us uber programmers. We didn’t have a requirements or specification or any solid target, no analysis of the problem domain had been done by anyone. The principal TDD advocate said, “Just start writing tests and it will all become clear.”
To which I replied “Bullshit.”
TDD is a good concept, but there are serious problems with test frameworks with content coupling creates code written to work to the test framework–not code written to solve the problem. Secondly, just writing tests will not magically let you know what the user is thinking.
In summary TDD is a good tool, it is not a silver bullet. Don’t get carried away.
@Everyone: Thanks for the support!
@Justin George: You’re right. And it is sometimes difficult because you have a case that somehow is already working, but it may not in the future. I don’t know exactly how to resolve this.
@Andrew Ingram: Good point!
@Michael Foord: Yeah, I usually have many times more lines of test code than program code. It’s usually because I write many tests per function, so I have all of the boilerplate test setup.
On another note, I think the idea is not to come up with solutions to your test. Do the simplest thing possible, which usually ends up looking like a hack. Don’t get into solutions until you really have to. You’ll be surprised what comes up when you do.
http://c2.com/cgi/wiki?DoTheSimplestThingThatCouldPossiblyWork
@Robert Cowham: Thanks for the article!
@Shawn Garbett: Yeah, it’s not a silver bullet. It still needs good programmers to do good work.
Test driven development can waste a lot of your time, you develop code to meet a test you never needed in the first place, where as if you’d just hack away and code what you wanted rather than worrying about the actual you could’ve been done by now.
I have many times made great code live up 100% tests passing and good coverage to discover, no it is all wrong and I didn’t need it. Even worse I found what was tested, was what was easy to think about and to write a test for what I needed would’ve required almost the exact program itself.
When you work with real world data and you do stuff like machine learning you can’t always rely on test first.
[…] still don’t do it that way very often, but this article presents some compelling arguments for that […]
It’s not an all or nothing issue. I worked on a math module that had to check a student’s answers, and we had to make sure the normalization engine didn’t oversimplify. The project was done in Scheme.
Anyway, we didn’t start our tests until our code was mostly done. It wasn’t done in an integrated way like you suggest. But it was certainly better than no testing at all.
The world is full of people telling us that you have to do certain types of programming or methodologies in order to be a trustworthy programmer. But at least with this one, you can do this part way and still get part benefits. That’s a good sign.
[…] [CODE] 6 Reasons to develop your tests first […]
[…] This entertaining article supporting test-first development has been playing on my mind. The article is beautifully written so it is easy to see the assumed context of working to deadline on well specified problems, most probably in a commercial environment. It saddens me though that we accept this implicit context across all discussion of software development practice all too easily. […]
[…] 6 Reasons to develop your tests first | LispCast […]
How is it possible to do top down design with functional/object decomposition using TDD?
Theoretically the first test you write would be the last one that passes. You would have to write a series of tests each testing lower functionality before hitting the bottom and then start implementing.
BTW I am test infected, just playing devil’s advocate here.
Eu sou brasileiro
Eu vo na padaria comprar pão!
Translate:
I’m brazilian
Thanks it really have change my life!
I must say, I’ve never been convinced about test-driven development, but I do love the pictures!
thank you, dude
[…] eu penso em TDD, escrever testes antes do desenvolvimento e tudo mais, não penso somente em ter uma ferramenta de compliance, teste puro […]