I was asked recently why I write tests for my code. This is a topic I have spent a lot of time discussing and teaching others about so I decided to write a post documenting my answers.
Let’s say a QA engineer finds a bug in a web application before a critical release. There is a set of objects that are not getting sorted properly and this issue is assigned to you. The sort is not trivial, written in Java, and utilizes sub-sorts and the list has over 100 objects in it.
The first thing most developers are going to do is try to reproduce the issue. There are multiple ways to do that. You can sign into the app and attempt to make changes to the code. You continue until you see the objects are sorted properly in the user interface. This may be an efficient method, but costly server restarts and constant refreshing of the browser can add unwanted overhead.
I personally would have attempted to write a JUnit test to reproduce the situation causing the bug. Tests can be run in a matter of seconds and can be utilized to cover a larger set of permutations. Once I can reproduce the issue I can simply re-run my tests to see if the issue is resolved.
The following week the same QA engineer finds another bug in regards to the sorting of the same objects. This is a different type of list but still resolves around the same module of code. A great developer would jump back into the code base, reproduce the issues, and put in a fix. Once they resolve the issue they remember the bug from last week. They test the bug from the previous week and notice this bug fix has broken the previous fix! Oh No! A small tweak fixes both, but if you were not such a great developer you may have forgotten to test the previous bug! Imagine if those two bugs were months or years apart? I have trouble remembering what code I wrote last week!
I hope you can see the point I am trying to make. By writing a test to fix the bug in the previous week, we now have a defensive test. This prevents us from changing the module in such a way that would cause the previous issue to get reopened. If we have some smart people on our team we would even have some type of CI (Continuous Integration) to inform us that something is broken. More on that in future posts!
Several years and a few dozen projects later you have a whole new array of fun things to work on. Fortunately, you still get to maintain some of the functionality you wrote many moons ago! New functionality needs to be added while preserving historic functionality. This is a tricky task and takes some impressive SOLID programming skills but you accomplish your task.
Luckily, there is some test coverage on this historic code. This helps remind you to think of some edge cases. It also gives you a safety net when changing the code that is working. You can ensure that it still works when you are done! In fact, one of the tests broke. You removed a couple of lines of code that did not look like they were doing anything. These removed liens of code break a very well named test. You quickly put the code back and enjoy an ah-ha moment of realizing why its there.
The requirements changed, as they always do, and you have to make some bigger changes than you expected. You make the changes but Oh No! A dozen tests are now failing. This is the cost that comes with writing tests. However, if you have written good tests, followed SOLID principles, and your code was written with testability in mind it should be a trivial task to fix them. After fixing these broken tests you now have updated documentation on how this code should work. This is not only beneficial to you, the person who wrote the code, but also the intern that’s going to come in next summer and attempt to break everything you fixed.
Honestly, you get a really great feeling when those red x’s turn into a green checkmark. Another happy moment is when you finish writing some quality code and all the tests pass. Or as funny as it sounds, you can get a euphoric sensation when you are finally able to create a failing test that reproduces a bug that you have been chasing for an hour, or two.
If you want to improve yourself as a software engineer learn to write tests. Try to write code that is testable and maintainable. Start to understand when you should write tests and when they may be unnecessary. As time goes on you will see that learning these techniques can pay dividends in advancing your career in software.
If you guys like this post please check out my series on Testing Your Code!