Automated tests like JUnit are a mandatory part of developing software. Recently I saw some bad things happening in a project that are good arguments for automated testing. I'd like to share them so they can be used as examples when convincing other people to test their software.
1. Killing Side Effects
After having worked in the mentioned project for a couple of months, I started bug fixing. That's always a good start in a new project because you learn how stuff works and get things done. My bug fixes apparently fixed the problems they were written for. However, after a couple of days multiple new defects have been found that were side effects of my changes. Because of the legacy codebase, I couldn't possibly foresee these effects. Had there been automated unit tests, I would have known immediately and would never have committed my changes. Automated tests make sure nothing breaks while making changes. Or: "Test until fear turns to boredom".
2. Tests as Documentation
In a meeting between all developers and the customer, we spoke about a defect the customer detected earlier. "The defect I found was caused by your modification of the abc-module" said the customer to one of my team mates. "What you described to me cannot be caused by my change" replied my coworker. "But you changed the code in that class, it has to be the reason. It worked fine until your change." Before the meeting, my colleague had time to look into the code. "No, it worked that way for years. My change had nothing to do about it." — "This cannot be true, the behavior is functional nonsense."
This went on a while and ended of course in disagreement. Had there been automated tests, not only had my colleague been made aware of a possible change in behavior. He also had proof that the behavior has been the same for years because none of the tests failed. This way, tests serve as a kind of documentation for business logic.
3. Tests Reveal False Bug Fixes
One of my coworkers wrote a small bugfix for that famous NullPointerException that haunts Java developers since forever. He did what a lot of us did since these ancient times: write an "if x is not null" condition. While this is really not pretty, it should solve the problem. But, surprise surprise, it didn't. 3 lines under this condition, the object was again accessed by calling a get-method. Because this call was outside of the new condition, it would fail with the same crunching noise as the first time. However, it would occur 3 lines later.
Had there been tests for that fix, this would have become obvious immediately. A lot of programmers think "Hey, this is a small fix in a small method. I can handle it, I know what I'm doing". That may be right and nobody wants to take this from you. However, an accident is an accident because it is not done deliberately. So, please write tests for every change!
4. Tests Talk to You About the Business Logic
One of my biggest achievements in the mentioned projects was the rewrite of a complex validator for (Excel) imports. The business logic was complicated and not documented at all. Of course it wasn't, would I write an article about that if it had been good code? During weeks of coding, I often asked the customer how different cases should work. Because of the complexity, a lot of changes have been introduced that where in conflict of the former implementation. The tests I wrote went red a lot of times and forced me to adapt my implementation. Often, the tests made me aware of border cases I didn't see myself. I could go to the customer, show him exactly what tests have been getting red and ask him what the right behavior should be. This was a very luxurious situation. However, this approach reveals lack of documentation and digs deep into the complex business logic. This is not always an effect the customer wants to see.
5. They Save Time
Yeah, I know. That's exactly the opposite of what customers, project leads and some developers are saying. "We don't have time to write tests, we have to ship this release, we have to deliver requirements — fast fast fast, hurry!" Maybe I'll write another article about why I think this attitude kills quality and weakens the software craftsmanship in the whole. However, automated tests do save a lot of time.
Imagine developer A implements a complex feature. He becomes acquainted with the business logic, learns the vocabulary and spells all this knowledge into code. With his deep understanding of that part of the universe, he can either decide to document and secure this knowledge into tests or not. Let's assume he's a bad guy or is being pressured into not writing any tests at all. Six months later, a defect is discovered in this part of the code. Developer B is send to slay the bug. However, he didn't have anything to do with this part of the application and now has to study not only the business logic, but also the code from developer A! So basically, he is doing the same thing as his coworker did a few months ago. Well-written, readable and running tests would not only show developer B that everything is working as planned by developer A.
These tests would also serve as a starting point to get into the code. Imagine to just have a look at the names of unit tests and discover that one of those describe exactly the bug you're supposed to fix. Just change the implementation of this test, see it turn red, change the implementation of the code so the test runs green and you are done.
Or imagine one of those Excel import monsters we're spawning again and again. A three-line JUnit test that reads an example import file, tests the validation and the conversion of the strings into business objects is such a great thing. This tiny test can be used to start debugging without having to start the whole application, wait for the connection to the server, wait for the UI to be brought up, click to where you can start the import, choose your example file, press start, change back to the IDE to see what went wrong in the logs. Boy, even tipping this bores me and sends my thoughts away to better places.
Writing tests when you write the implementation code does save time, so do it!