When asked "Do you write tests?", a lot of developers these days will
say "of course" as their answers. However, not everyone can admit to
doing TDD (Test Driven Development) correctly. Test Driven Development
says, a developer will write a test that fails first, then write code
to make the test pass, and refactor when possible, and repeat. This is
what most people's TDD rhythm is. For the most part this is fairly easy
to do. But to reach the next level, one has to understand TDD as a
tool: TDD means more than just test your own code. Here is a couple
tips on what the last "D" means:
Discipline
It
takes a great deal of discipline to even write a failing test before
writing the actual code. Sometimes, we write a little seudo-code here,
or move a method definition there, or changing code else where trying
to see if more new code needs to be written after it, and sooner than
you think you are writing the actual implementation of the methods you
wanted to test (Test Afterwards Development anyone?). Other times you
write the test, but you are too anxious to even run it and see it
fails. And other times you want to jump into the actual code
immediately when you see your new test fails, but failing for the
unexpected reasons.
Don't fall into these traps. If anything is true, testing is hard, but it is at the same time rewarding and fun. What's also true is, it will pay off.
Write the failing test, draw up your list of tests you will need to
write, and satisfy them one by one. Having discipline is the
cornerstone of becoming a better programmer.
Design
It
takes too long to write a test? Tests are running too slowly? Are your
tests difficult to read? Are they too brittle and fail all the time?
Hang in there! You ever had the feeling you saw code in the codebase
that irks the living hell out of your mind written by someone else on
your team? Well, it is time for you to get some of these feedback about
your own code. Yay, your code sucks! Your tests
are telling you that! Let's address each of these one by one.
Slow
running tests? You shouldn't be hitting a database or web service in
your unit tests, because you can mock/stub them out. Difficult to
mock/stub it out? There probably is a better way to design your classes
your tests are hitting. Ever heard of Inversion of Control (or
Dependency Injection)? Master them. True TDD masters use them
extensively.
Unreadable tests? Is it because of too many
mocks/stubs? Or is it the code is 500 lines long and doing high octane
720-double-backflip logic? Either way, you have to learn to like small
objects. Check this
blog post of mine out.
Hard
to test something? Tests too brittle? Perhaps you have encapsulation
issues in your class design. If your classes are referencing 15 other
neighbors, of course they are hard to mock/stub. Chances are, you have
to spend time to debug your tests to find out what's wrong! Heard of
Law of Demeter? Even if you have, take a look at this
highly entertaining yet informative post. It might change your perspective a little.
The
bottom line is, TDD is a way to guide you to writing good code, but
only if you know how to use it as a tool. Now that you know, hopefully
you will have a new perspective next time you write a test.