setUp()
Much has been written on the subject of automated testing, whether it be unit tests, integration, end-to-end, or any esoteric permutation thereof. As with everything these days, there are a multitude of opinions on the subject, from those prescribing a long list of complicated rules for automated testing, to those who say unit-testing is overrated or a waste of time. Then there are those who like to sound smart and politically-correct by answering âIt dependsâ to every question, which helps absolutely no one improve.
You will not find that in this article. This is a highly-opinionated piece on what has helped me improve my testing practices, and more importantly, as will be mentioned later, the quality of my code. Take what you will and apply it your own development. If just one item from this article helps you in the slightest with your code quality, then I have accomplished my goal.
I will be presenting code examples mostly in Go, which is one of the most popular languages used today for cloud and microservice development and my favorite language currently. In some instances, Iâll also present some examples in Java to reflect the OOP model of other common languages.
The Why
It is a well-known fact that fixing a bug after a product release is much higher than if the bug were uncovered during the development or quality assurance phase. For example, quoting from Celerity:
The
Systems Sciences Institute
at IBM has reported that âthe cost to fix an error found after product release was
four to five times as much as one uncovered during design
, and
up to 100 times more than one identified in the maintenance phase
.â
The same article mentions that
âA 2003 study commissioned by the Department of Commerceâs National Institute of Standards and Technology found that
software bugs cost the US economy $59.5 billion annually.
â
The message is clear: the earlier in the development process a bug is detected and resolved, the faster and cheaper it is to fix it.
When I started my career in software development in the year 2000, automated testing, of any kind, was not yet a widespread practice. In several of the companies I worked for initially, there was an entirely separate QA team that would test a release before it was pushed to production. I remember writing what seemed to be beautiful code for new applications which worked perfectly locally, only to have my ego shattered when it was deployed to the QA environment and the QA team tried thousands of ways to break my application, AND succeeded.
In the end, though, I was happy the QA team found these issues, as it meant they would not make it to production and affect actual customers. On the other hand, when an application was in its maintenance phase, adding just a few enhancements every few weeks, the QA team spent more and more time testing the application, not just for the new features, but also all the existing functionality to make sure nothing broke as a result of a new feature. This was a very tedious process for the team and, as a result of being human, some of these manual tests were either overlooked or skipped in the interest of time, only to result in a bug in an existing feature making it into production. This would end in lots of finger-pointing between the development and QA teams, with the QA testers asking âwhy did you introduce this bug here?â and developers saying âwhy didnât you catch it during your testing?â.
It was around the year 2008 when I first learned about unit-testing, which marked a turning point for me in my career. As I started writing tests, and eventually doing true Test-Driven Development and BDD, the quality of my code improved, the amount of defects that made it into production was just a small fraction of what it was before, and being on-call was no longer something I dreaded.
I have learned a lot about testing since then, and Iâm still learning about it each day. With this article, I hope to impart my lessons learned so that we can continue to move the needle in this exciting field.
Besides the reasons above, remember this: well-designed code is not necessarily easily testable, but easily testable code is usually well-designed. If you want to improve the quality of your code (which is the REAL goal out of all of this), then make your code easily testable. The best way to guarantee this is by writing your tests first.