“Man, I just love unit tests, I’ve just been able to make a bunch of changes to the way something works, and then was able to confirm I hadn’t broken anything by running the test over it again…” — http://stackoverflow.com/a/67500
The benefits of unit testing are well known, as are the many reasons that are offered when asked “Why don’t you do it?”. The arguments I hear over and over are:
- “It takes too much time.”
- “Our code isn’t suitable for unit testing.”
I’ve discussed unit testing with many people in the past years and at some point, I discovered one of the main reasons behind the arguments that were actually offered. We human beings find it much easier to say “It’s not possible”, “It’s too expensive”, “I don’t want to” or “I won’t start doing this until I’ve seen it work” (this one I encounter surprisingly often and makes me smile nowadays) than to admit:
- “I don’t know how”
Why not to Google for “Unit Testing 101”
Frankly, Googling for “Unit Testing 101” and “Unit Testing Tutorial” is just useless and maybe even harmful when you, like many developers out there, are working, day in day out, on a code base that exhibits many reasons for wanting to do unit testing: low modularity, tight coupling, lack of documentation and a constant dread that something will break without you knowing. The search results you’ll find, well, the authors all offer beautiful, gorgeous examples that don’t require any refactoring at all. And here we’ll just instantiate the class in our test framework and call this or that method. See? It works, yay! In fact this article explains it even better: It’s easiest to test leaf nodes of your dependency graph.
I have found myself in many discussions on the merits of unit testing (my own fault really) and I have come to realize that my introduction to unit testing was very different from that of many developers: I was taught unit testing by developers who had been employing unit testing for years, in an application landscape that is heavily coated in unit- and integration tests. I can honestly say that I feel about unit testing much the same way as the quotation at the beginning of this blog post. It’s a wonderful tool and my first introduction gave me an opportunity to learn how to do unit testing in a code base that empowered me to write unit tests. When I first learned about unit testing, the code base itself was not working against me, but with me. Unfortunately, few developers have that luxury..
There’s a great book out there, Working Effectively with Legacy Code by Michael Feathers, that shows all kinds of techniques that can be used in legacy code bases, code bases that give you a hard time when you want to start unit testing them. And there are plenty more good books out there. However, books alone are insufficient.
Firstly, you really need to want to do unit testing. In fact, not just you, your entire company, including management needs to want to incorporate software quality best practices and needs to emphasize this regularly. If you’re hearing “The customer wants this quickly so you’re to create this quickly with minimal effort” or if you’re telling yourself “Just this one time, we can skip them”, it takes a whole lot of effort to get unit testing in place…
Secondly. When you’re just learning to drive, there’s an instructor next to you who navigates. You’re already having to learn how to drive and that’s a challenge enough in itself. Learning how to do unit testing while at the same time having to refactor your code base to be able to do so is tough. But frankly, saying “I can’t learn how to drive because I don’t know how to navigate” is harmful. On the other hand, you get people who say “If and/or when I start driving, it has to be perfect” and they spend a lot of time bickering about how driving (unit testing) should be done even though they’ve never driven a mile.
Some people will point out that a colleague who wrote his first unit tests “fucked up everything”. Please, stop finding fault with tests or refactorings that aren’t perfect. Instead, start appreciating that someone tried to learn something new. (And if he really did break something in the code, where were you at the time to either review the code or help him fix it?) Please, stop finding fault with techniques that assume your code base is clean. Instead, start cleaning up your code base. Please, stop finding fault with books whose advice ‘doesn’t work’. Instead, regardless of whether you’re right on a particular piece of advice working or not, start looking for what you can learn or adopt. Heck, I don’t like every book I read from page 1 to the end but I always find at least one thing that is useful, new or interesting. And most of all, stop arguing about how you think unit testing should be done and find a place in your code base where you can start doing it.
The absolute minimum
I’ve called this post “Unit testing 001”, because I think that most 101-like approaches are already to heavy handed. If you are already familiar with unit testing, you may think that these posts must be the minimum to get started. (Why else would they be called “Unit testing 101”?) They’re not. They’re either an essay on why you should be testing, or a huge list of things you should be doing or looking out for.
Here goes. The first, very first thing you need:
In order to unit test a class you need to be able to instantiate it (*)
(*)with each and every one of its public constructors! Don’t cheat by creating a new constructor for unit testing purposes!
- Not throw any exceptions, before during or after running the test(s) for valid input data
- Not trigger any debug breaks, before during or after running the test(s). EVER.
There. That’s it.
Don’t think you’ve achieved anything yet if you can do that, but if you want to make some (any) progress at all, this is the bare minimum: you need to be able to instantiate the classes you want to bring under test.