After deciding that "learn about unit testing" was going to be my new years resolution, I just went on with business as usual and pretended nothing happened. Now, a year and a bit later, I finally did what I promised myself I'd do at the start of 2012.
It may have been the recent migraines messing with my common sense, or Chris Hartjes' relentless battle for unit tested code on Twitter, or having randomly picked up his building testable code ebook during sale a few weeks ago, or the voice whispering in my head that I would be in big problems if at some point in the undetermined future a very crucial "calculateTotal" method would end up borked.
I'm not sure what, but something triggered it.
Learning Unit Testing with PHPUnit
So last weekend, I set out to finally learn how to unit test my code. I was going to start with baby steps. Just this one calculateTotal method that I was worrying about. So I grabbed my ebook, read it, and opened up Terminal to follow the instructions.
By the end of the day I had ran out of unique cursewords, nearly wiped my entire MAMP-powered localhost and had given up on unit tests completely (about three times).
Oh, and I also added unit tests covering pretty much all methods in this (admittedly still small) project.
You know, unit testing has always been one thing that I never considered vital to a project. I am careful when I release stuff, and every fix gets tested properly. In the browser, clicking around. Reading code extra carefully. PHPStorm's excellent code sniffing. Nothing major could possibly slip past that.
PHPUnit forced me to reconsider.
Discovering Bugs that couldn't possibly exist
I initially thought I broke PhpUnit (again) when it was telling me that a certain sanitize function wasn't living up to the tests. I had previously tested it, and while stepping through the code, it all looked fine. It must have been PhpUnit. But no. It turned out the entire method was busted in a very subtle way, and it basically left my entire app wide open to XSS and CSRF attacks and possibly even worse. My first, and quite crucial, line of defence was broken from the start without me even knowing.
If I hadn't unit tested that method, I would have quite possibly never figured out it was this badly broken, until someone else did (accidentally or on purpose).
I also wouldn't have found two other major (and similarly hard to spot) bugs in other code that I considered solid. This code also passed my "clicking and reading" test before.
So, if you write code but don't unit test it yet because you are already testing your code, it's time to fix that.
Steps to Take
- Get Chris Hartjes' book: The Grumpy Programmer's Guide To Building Testable PHP Applications. It's a great and easy to read ebook that covers basic and more advanced object oriented programming methodologies that make it so much easier to test code. It's loaded with examples too. If you don't know how to apply dependency injection yet, you have no excuse not to get this ebook. He's also working on a new ebook specifically about testing with PHP Unit.
- Take/plan some time to read about and get phpunit running on your machine. This was by far the most troublesome thing I had to do and what caused the swearing and almost nuking my entire localhost to start from scratch.
- Set some goals on what you want to test and just do it already. Start easy - take one vital method and test if every line works as expected. I wouldn't suggest going for 100% code coverage right away; give your new testing addiction time to grow and to get better at writing tests.
- Do it. And tell others who don't test code yet, to start doing it too.
I've been in the camp of "I already test my code" for a long time, but I've finally experienced first hand the power of automated unit testing.
It's good to test and think your code is working, but it's awesome to know it actually is, too.