Automatic testing and continuous integration have become a some what standard in modern day software development. Even though I have noticed by experience that automatic testing does indeed reduce the number of bugs found from the software, not everyone is fond of writing unit tests. This blog post gathers together some of the objections against unit testing, which I have heard during my career, and gives my answer to each objection.
Objection: Writing unit tests during development is too slow and costs too much.
The most expensive phase of the software’s lifespan is the maintenance phase, not the development phase. The target of the development phase is to build a firm foundation for the maintenance team, which is usually working with the created piece of software a lot longer than the development team. The problem is that without unit tests the firmness of the foundation cannot be verified. And even if the foundation would be firm, the maintenance team would still face maintenance hell, because they cannot be sure that the changes they have made to the application are not breaking anything. And when the changes break something, it can be really frustrating to debug a bug when a comprehensive set of unit tests is not available. To avoid the deployment of broken code to the production, the maintenance team has to spend more time for verifying that the code is actually working. This costs money, and can result to a lower customer satisfaction, when the promised changes are not available in the expected schedule. Thus, it makes no sense to try to save time and money in the development phase, if it costs more money in the maintenance phase.
Objection: Writing unit tests is too hard.
This is a classic indication that the code should be refactored. Writing unit tests for a spaghetti code can be extremely frustrating. In this situation the best solution would be to identify the different responsibilities of the existing code, and split the code in to a smaller fragments, which are easier to test. A following principle should be followed during the refactoring phase:
A method should do only one thing.
I have noticed by experience that methods that appear to be too hard to test, usually have got many responsibilities. Thus, splitting them in to a smaller methods makes the code a lot easier to test. Instead of making excuses, the developer should take responsibility of one’s code and refactor it.
Objection: Unit tests are preventing the further development of the application, because the tests are not passing after changes were made to the business logic.
This is by far one of the most unreal objections I have ever heard. I find it a bit too surreal to believe that a developer does not understand to modify the unit tests, if changes are made to business logic of the application. Somehow I cannot really believe that this objection was the real reason for not wanting to fix the unit tests. I believe that the objection was caused by either a very tight and unrealistic schedule or the developer’s negative attitude towards unit testing. Anyway, tackling this kind of problem can be a bit problematic, because the first reaction of a skilled software engineer should be WTF. Perhaps the most sophicasted way would be to point out that unit tests can also be refactored and changed based on the needs of the tested application. If this does not work, the second best solution is trying not to end up working in the same projects with these developers… ;)
Objection: Due to our busy schedule, we cannot write unit tests now, but we will write them later (TM).
This cause of this objection can not be found from developers. This kind of objections are usually raised by managers, who have set unrealistic deadlines, which are impossible to meet without sacrifising the quality of the created code. The problem with this kind of approach is that the developers usually have got no time to write unit tests to the created code, because the next project is already waiting for them when the previous one is deployed to the production. A situation like this does the company more harm than good in the long run, but sadly it can be very hard to solve. Even if the developers would want to write unit tests for the created code, they do not have the right to make decisions like this. Sadly, if they cannot talk reason to the management, perhaps they should be looking for other job.
Objection: The class is so trivial that unit tests are not needed.
In some cases this might even be true, but last week I run into a method, which was used to compare the contents of two InputStreams given as a parameter. It had no unit tests, so I started writing them. During that process I found out that the method fails, if the first InputStream is empty. However, since I had the unit tests to back me up, I was able to fix this bug in a short period of time. This episode was a good lesson for me, because it did prove that I had been right, when I have argued that only setter and getter methods can be left untested as long as they do not contain any logic. Do not fall in to the same pit than the original developer of the method in question. Be committed for unit testing and just write the tests. And remember, if the code in question is trivial, writing tests for it should be very easy and fast process.
A word of warning though: Unit testing is not a silver bullet. However, if used correctly, it can be a valuable tool for ensuring that the written code is working as expected. It is extremely important to understand that a good code coverage does not reveal anything about the quality of the written unit tests. The quality of unit tests should always be verified by using code reviews or other kind of manual inspection. Remember that writing unit tests is not good enough. The power of unit testing is really unleashed, when writing good unit tests is the common goal of all developers.