Why write unit tests?
In this article I want to talk about unit testing. Why do we write them? What do we expect from them?
I have heard many different opinions, sometimes quite opposite. Some may argue that unit tests are not that important, and sometimes are just a burden that prevents from moving fast. Others claim that they actually allow to iterate faster and they are more important that the code itself.
I think that the truth lies somewhere in between. When written poorly, unit tests will indeed will create obstructions, draw resources and slow you down. When done right, unit test suite will allow you to go fast and don’t look back checking if you have broken anything.
It takes skill to do it right, but first and foremost, it is crucial to identify what is the expected result, what do we want from unit tests.
In my personal experience, I have seen following benefits from good suites of unit tests:
-
Verification of correctness. The obvious way to check if code works is to run it. It is OK to manually run and verify the result as long as the application is quite primite. As soon as it becomes bigger than several logic structures, manual verification is no longer a valid option. But we can use other code to run our code - tests. The test will run the desired piece of code and verify if it does what is expected.
-
Bug fixing. Test don’t fix bugs themselves, but they are the best tool to narrow down the problem and to ensure the fix works (and also that it keeps working in future). You can write a test for a piece of code under suspicion and make test validate if the result produced by code matches expectation. If it does - code is OK, if not - even better - the problem has been found. Now keeping the test in place, you can fix the bug and the test will tell you right away the problem is gone.
-
Better code structure. Writing tests is useful to split code into smaller, more meaningful functions with sole responsibility. Especially if you follow TDD, the code will naturally grow better-structured with proper dependency injection and separation of concerns.
-
Documentation and specification. Unit tests are a great tool for code documentation and specification. A good well-written suite of unit tests can tell much more about how code works. It clearly states what are the possible inputs and expected outputs. Moreover, a suite of tests will always be up to date, it cannot become neglected as a wiki page can.
-
Facilitate changes and enable refactoring. It may sound counter-intuitive, but a good suite of tests makes it easier to make changes in code. Good tests verify only interfaces, not implementation details. It gives engineer an opportunity to change internal implementation and still be confident that the code is correct. As soon something breaks, the tests will tell exactly what. This makes a feedback look very short. Unit tests allow to make changes safer and faster.
-
Communication. Unit tests is a great communication tool. As mentioned above, unit tests are a great documentation. And it stays relevant over time. A good suite of tests communicates authors intention, what the component does and to expect fom it, both to other team members and to author himself (try to remember intricate details of behavior several years after release!).
Overall, in my experience unit tests proven to be an extremely valuable tool that gives me ability to build systems that are error-free and are easy to maintain. It may take time and require a paradigm shift to fully appreciate all benefits of good unit test suite, but the reward is great. A good suite of tests is a good investment that pays off in a long run.