This is not a revolutionary statement.
I am not the first to say it. I'm sure I learned it in a textbook, and forgot it.
It should be core to our process. It should be a necessary skill that is taught and enforced. It should be a requirement before shipping code.
But the reality is, it isn't. Testing is fungible. Testing is an 'ought to have'. Testing is the first thing to get cut.
It is easy to rationalize away. I'm guilty of it too.
Unit Testing? What's that?
In college, we had 'tests' our professors would give us as guide posts to ensure our projects met the bare minimum requirements. Mostly, these were sample inputs and outputs, rarely, these were bash scripts. Each professor had a different way of defining these tests, never using formal testing frameworks.
This lack of unit testing was compounded when I started working for "real companies". Millions of lines of code, and no unit tests. Ask one of the "architects" of the system, an engineer with a career spanning more years than my age, about unit testing, and you'd hear a cynical response. "Thats a waste of time and money. We have an entire team of Quality Assurance Engineers. They are good at finding our rare mistakes".
I was skeptical and cynical of unit testing because I never properly learned how to unit test. I never got to experience the benefits having a good unit testing suite with good coverage. Because of this, I would focus on the cons list when reading about unit testing. I was lead to believe testing was someone else's job.
Testing is difficult. Developing a testing culture requires investment. Testing will slow down development.
Learning & unlearning
A few years ago, I started to re-evaluate my stance on unit testing. It helped that I had starting working heavily in Ruby, a language where tests are expected. I started reading books, listening to conference talks, and more importantly, starting writing unit tests. I wrote a lot of them, often times writing more lines of rspec tests than code. I would write unit tests that tested all the branches that existed in my code. I wrote tests to achieve near 100% code coverage.
As I continued my education, I started deleting low-value tests to speed up my unit-tests. I strived for fast-feedback. I'd configure my editor to re-run tests on each save. I'd monitor the code coverage.
I set up tests first, on a new project, so testing was not an afterthought. I would slow down my development to ensure I was testing as I went along.
I continued learning, re-evaluating my understanding of Object Oriented Design. I read POODR & 99 Bottles of OOP. I recognized that software comprised of truly decoupled units was easier to unit test. I saw the benefits of SOLID & STABLE code.
The Benefits of Unit Testing
Having unit tests that can provide fast feedback enables a new level of development. It enables developers to make a change in code, predict the outcome, and test the expectation, in a matter of seconds. It enables developers to evaluate their code and refactor it - that is, make modifications to the code without modifying the behavior. It makes development safer. It enables developers to talk concretely about their changes, "I know" vs "I think".
Looking back and comparing how my code has evolved over the years, there one significant, overarching pattern that has emerged. Code that is easy to test is likely easier to understand and modify.
I can unit test, and so can you!
The hardest part of unit testing is starting. This pain grows exponentially by the number of lines of code written without tests. Have 10,000 lines of code in a legacy application without any tests? Yes, setting up tests will be painful. You should still do it. That doesn't mean you need to write unit tests for all of the code. Fixing a bug? Write a unit test that exercises the code path where the bug exists. Writing a new feature? Write unit tests that test that feature.
Setting yourself up for success early in a new project is best way to foster and grow a unit testing culture. Develop a boilerplate that has the testing framework already set up. When the batteries are included, it lowers the barrier and hesitation to enter.
As the use of a unit testing culture develops, it will eventually reach a self-sustaining cycle. New developers added to the culture will see the emphasis of unit testing in the code base, and do their best to follow the pattern they see. Further, having developers who are proficient at unit testing means you have a set of teachers ready to coach those without a strong unit testing background.
Does writing unit tests slow down development? I can't say this with any authority, but, based on the anecdotal evidence of myself, the answer is no, not in the long run. There will be a ramping up time where a developer needs to learn how to set up the framework, and write unit tests, and how to run them. But, that is a sunk cost - it needs to be paid once. The unit testing will help catch bugs earlier. It will prevent a broken build from being merged. It will likely speed up development time in the long run.
In no particular order: