Test Driven Development is a well known technique to produce well tested code. I first heard about it around 3 or 4 years ago from a colleague but only came to apply it in a coding dojo myself for the first time a little more than 1 year ago.
A process to reliably “generate” unit tests
The idea is to write a (failing / red) unit test before actually implementing a part of the functionality itself, then implement the functionality until the test is successful / green. Then write a next failing test for a different case or parameter or whatever you like, and continue this cycle. It really is that simple.
If you wonder why, here are some advantages TDD gives you:
Refactoring? Not for me, my code is perfect!
Or so you think… is it really though? Can anyone else maintain it? Why are there these nested if cascades, endless switch statements, or even more basic, what is this variable for?
The amount of tests produced by TDD for a even a tiny bit of code makes you really fall in love with it, as there was no problem refactoring the code. You can be quite sure, that you still have a piece of code working correct within your defined tests.
Trust your tests for complexity
Requirements change and everyone working in software for more than a month or so knows this.
TDD also helps the functionality to grow organically with the requirements: You thought attribute A of your class is sufficient as a boolean / integer / string? Well, with the new requirement, you better encapsulate it as a full blown class, with separate functionality. Since you have a lot of tests covering your class, you can start extending A as a new class, and implement until all of your tests are green again.
Unit tests are saving you time, really!
Ever said: “Yeah, I am going to write a test after I am done implementing” and then just went to your integrated to quickly to a “developer test”? Ever thought you’d rather not touch this weirdly looking piece of code, because who knows what might break? These two things are probably happening on the same piece of code.
When you use TDD you will automatically have tests, and you can run them quickly, whenever you work on something, or nightly automated. No need to click through 100 scenarios to be sure moving this variable a bit up to remove another nested loop did not break any fancy case you had not had in your mind in this moment: Try it out and see if it breaks.
You will get better code, I promise.