Skip to main content

Tests first or tests last - come on, who cares?

Posted by johnsmart on June 2, 2008 at 3:44 PM PDT

Let's not be pedantic. Write unit tests before you code a method, or after it - in my experience, it matters little, as long as you think about and write the tests at roughly the same time as you write the code. It's coming back to do the tests later (or not coming back at all) which causes problems. Personally, I like to write unit tests just before or immediately after writing small chunks of code - it doesn't break the flow, because it is part of the flow.

This takes a little practice - inexperienced developers often have trouble knowing what tests to write. But this may reflect the fact that they are unsure as to what code to write as well. Some people have commented that TDD can encourage micro-design - very low-level design without taking into account the bigger picture. This can happen with inexperienced developers, or if you apply the approach too pedantically. This is where approaches like behaviour-driven development are cool. Do you write a unit test for a getter method before you write the getter method? Then maybe your unit tests should be a little more high-level, and closer to the user (or system) requirements.

But getting back to the fundamentals, why do I like unit tests in the first place? Simple! My practical experience tells me that they help improve code quality, and save time debugging. The upfront time taken to write ten small unit tests is much less than the time taken to fix bugs later on that would never have happened if the code had been unit-tested correctly.

Indeed, I frequently see coding problems that would never have occured had the code been properly unit tested. A recent example: over an hour hunting down a problem in a web application, in what appeared to be correctly-written Spring-MVC code. It turned out that a validator class was swallowing an exception. We found this problem easily, immediately in fact, upon seeing the code (code reviews are effective, too). But, the point is, we spent an hour or more finding the right class to review. And this problem would have been detected, and fixed, very quickly if the code had been properly tested.

In my experience, when people set out to write unit tests after the fact, they write them poorly, as an afterthought ("I've finished all the code, now I just have to write the unit tests"). Or not at all. In this case, is the code really finished? Well, if it works perfectly, it is, in which case, writing the unit tests looses a good chunk of its value proposition. But often it doesn't, and the unit tests written afterwards will be superficial, and will not always test the code well. Or, developers run out of time and don't bother with testing at all.

TDD is like any other coding practice. When you are learning any new technique, you tend to follow the instructions to the letter. Similarly, when you learn a martial art, you try to duplicate the master's movements to the letter, without necessarily understanding the underlying logic. Once you are familiar with a technique, having experienced and worked with it, you understand it better. Then you can improvise, and mix the new technique with other ones that you have previously mastered.

Related Topics >>

Comments

I like unit test. I think they are useful. But I often write them after the code is finished. I think any good developer does check the code once it is written. Unit tests provide good tools/frameworks/methodology for doing that. From my experience it was more often not possible writing good unit tests in advance: it was always needed to provide a context for testing. And the context usually depends on the implementation. So I would say "befor or after" is a matter of taste if one realizes the need of proving written code quality.

No one proclaimed anthing about not taking the bigger picture into account if you are referencing my comment. From my experience, it is not very encouraging to produce quality code if you force rigid rules on how to test the part of a design. Being dynamic is good for your software architecture at the end. Being rigid is old school and will only get you to where you have orginally left. The no good parts you left in your design for the purpose of following strict design specifications will come back and haunt you. Especially if you are writing an API which must be backward compatible with future versions. On the other hand, unit testing is only refered for server side development. It is not very easy to unit test for example User Interface libraries. Hence it is not always right to round up all software testing domain as "unit testing".

You can stricly learn the katas that your master taught you and use them well but someone who improved the same technic while learning will always beat you.

Write a little, test a little :) It's just the only way I know to write code I can (reasonably) trust.

My (pretty) extensive experience on the topic of unit tests is that if you don't write them first, you just don't get around to writing them. Writing tests before writing code is fun and feels purposeful. Writing tests for code that "already works" not so much.

+1 completely agree

I find I like writing code more than I like writing tests, so I like to start with code and write tests as I go. What the tests really do for me is to allow me to confidently switch focus to new code by allowing me to forget code or hand off code to others. If I've got tests that show things are working, I can let go of things. That's not to say that having tests means the code is problem free. Like John said, it's a matter of experience to realize whether the tests you've written are 'good enough'. I don't think I'm quite at that point, so I tend to write more tests than I probably need. But more tests never hurt anyone. :)

I think if your development process is task based, like Scrum, you are only finished with a task if there's a test. It's supposed to proof that your code does what its supposed to do. So no matter if your are writing your test before coding or afterwards, there must be a test case. The quality of that test, you are right John, that's another story.