What is worse than having no unit tests?
Answer: Having unit tests that don’t fail when they are supposed to.
Unit testing is hard, I know. Especially for new developers. But forcing them to unit test just to say “we have unit tested” may cause more harm than good. If they don’t take the time to really understand why we unit test and how to test correctly they are much more likely to write bad tests which provide a false sense of confidence.
Why do we unit test?
There are many reasons but to me the least important reason is to produce fewer bugs. That is a valuable by-product of course but I think there are much better reasons to unit test. Unit tests:
Help us gain a deeper understanding of our own code.
Its all too easy to make assumption about how own your code works. I have lost count of the number of times that a failing unit test left me confused and dumbfounded only to find that my code wasn’t doing what I thought it was.
Produce code that is better architected (decoupled, extensible, flexible) with fewer code smells.
Unit tests are REALLY hard, if not impossible, when the code being tested is coupled, handling multiple responsibilies and overly verbose. When unit testing is hard that is a code smell that you need to work on your architecture/design. Once you are comfortable with unit testing in general, writing tests for well designed code will be easy.
Help us gain deeper understanding of our tools/platforms.
Almost all languages/platforms/frameworks offer some type of unit testing facility. If you are looking at one that doesn’t have a good unit testing story, find another tool. Using these testing framework will help you understand the inner workings MUCH faster than implementing production code. Think about it, the point of unit testing is to isolate some functionality and quickly verifing its working as you expect. This is a perfect tool for understanding the intracies of a language. I most recently did this with Chef Cookbooks and ChefSpec (rSpec).
Provide for faster regression testing after refactors.
How will you know what effect code changes/refactoring will have on your system without a unit test suite? You need to be able to make code changes and get unit test results in minutes/seconds if you want a fast feedback loop. Without the confidence of good unit tests your just rolling the dice every time you make a change.
How do I unit test correctly?
Whether from a book, blog post, another developer or trainer, everyone has heard the following phrase in the context of unit testing or test drive development:
Red, Green, Refactor
But have you practiced it? Do you know what it really means? Here it is in short, simplified terms
Red = See the test fail when expected situation is broken
Green = See the test pass under the expected situation
Refactor = Improve your tests
It so easy to try to skip the process and “save time”. If you aren’t seeing your unit test fail under the expected negative conditions how do you know if your test even works? I have skipped this step in the past and it almost always bites me later. You could spend hundreds of hours on thousands of tests but if they don’t fail when they are supposed to, they are worthless.
This is especially hard when trying to add unit tests to an older project that was not built to be unit tested. We see green and think its done. YOU MUST MAKE SURE THE TEST FAILS CORRECTLY. Temporarily comment out the code being tested, call the wrong method, pass the wrong variables or whatever you need to do to run the tests and validate the unit test fails as expected.
“Fails as expected”
Its good to validate the test fails but is it failing for the reason you expect? Decide how it should fail (the exception that should be thrown for example) before running the test and then verify that it is failing for the correct reason. If it doesn’t this can only mean you don’t understand how your code works or the test is not written correctly.
Unit testing in new platforms or languages
I have found unit testing is especially valuable when learning a new platform or language. I’m new to Ruby and Chef but through unit testing I’m learning the inner workings of both technologies and gaining a working knowledge much faster than writing only cookbooks.
I am very passionate about unit testing (if you couldn’t tell already) because it works! Even today I found that half of the tests that I had been working on for two weeks in Chef were all wrong. I simply commented out some code expecting a test to fail and it didn’t which led to the identfication of a sweeping problem in my tests.
Don’t make the same mistake.
Use unit testing in your development process but make sure to understand why you unit test and the correct process.
The best book I’ve read to date on the topic of unit testing has been The Art of Unit Testing by Roy Osherove. I highly recommend you read it if you haven’t.