After spending a whole year motivating my team to focus on automating integration tests even at the cost of creating less unit tests, suddenly we ended up with my team being pushed a bit from various stakeholders to start investing more in unit testing again.
Recently I’ve started to create an iOS app in the Swift programming language. As I’m a nice guy and by the way very open minded and all that, I decided that also in case of my own app I would try out and be serious about doing unit testing.
Although what I’m doing is not exactly Test Driven Development (anyway, which people being honest to themselves would say except Kent Beck that they are doing 100% TDD? :)), I really try to do it properly and see what it takes and what is gained via doing lots of unit tests.
On the price tag side, it is painfully obvious why most people give up or don’t even seriously try in the first place: compared to just writing the code quick and dirty, completing it with unit tests written, and refactored to be able to write even more unit tests and bugs fixed that otherwise wouldn’t have surfaced either for a very long time or ever, took roughly 8 (eight) times the effort! So the challenge is given: prove me that this is worth the hassle and the investment.
On the gain side, I’ve known the traditional perceived benefits of unit tests for quite a while, but they didn’t really convince me in the first place that it was economically rational to invest in: Lots of hidden bugs fixed (but how many and how serious?), and having a safety net for refactoring later, so that I can make sure I don’t break existing behavior of the code deep inside when restructuring (but I’ve just started my app, so no big refactors needed so far).
However, what surprised me a bit, and became very quickly clear for me that it was a great thing to do unit testing, is this: When you create unit tests, and you want to do them properly, so not just to fulfill a line coverage measurement tool KPI, but to really try to test all possible ways of things going wrong, you end up doing small refactorings of your code (á la Martin Fowler refactoring, not “let’s rewrite the whole codebase from scratch because another idiot used to write it in the first place” kind of “refactoring”). These small structural improvements do you 2 enormous favors:
1) When you debug your code later on, you (or more likely, someone else) will be able to find your way around, know where exactly you are in your search for the problem rootcause, and identify where the bug is much quicker. And by much quicker I don’t mean 2 hours instead of 3 hours, but like 2 hours alone instead of 3 DAYS, including constantly entertaining your colleagues.
2) When you want to implement new features or extend / change existing features in your code, you’ll find it much easier where the change needs to happen, and the change can be more isolated and simpler. Therefore, it is very likely that you’ll end up introducing much less regression issues and your new code will have in general better quality (but this is more or less the same safety net thing I already talked about).
All in all, this is still fuzzy non-manager-convincing artist-developer gibberish, but at least I myself am a bit more convinced. So if you face the unit testing / TDD flame war next time, try to convince the priests of the no-unit-test religion to give it a try themselves, preferably with some coaching / pair programming involved, and see for themselves how it goes.