Test first, it's better than history.
April 21st, 2007
When I first began to adopt the Unit testing mindset, I looked at it as a chore. It’s pretty obvious how non-motivating the thought of going back to a project to write tests can be. So I eventually gave up on the idea of testing and just hack-tested as I went along programming, expecting the things I tested at the beginning of the project to just “work” as I went along. The flaw with this (obviously) is that once you get further into a project, you’ll inevitably make changes along the way that affect things you’ve already “tested,” and a series of breakages will occur that you’ll spend hours and hours debugging only to have that moment of “oh yeah” later. After several years of this nightmare, I decided to look at testing again – this time with a fresh look on when to test and what to test.
I’ve been using Ruby on Rails now for several years and it’s made me an infinitely happier programmer. Besides being built on a cool language like Ruby, which lets us Ruby programmers do all sorts of cool things, Rails has a plethora of built-in testing methods that make testing so easy “you’d be stupid for not doing it.” But that still leaves us with the same problem question when we’re done with a project: “well it’s done now, do I have to write tests?”
It dawned on me sometime back when I started “testing first” that this problem is much like the difference between Math class (which I enjoyed) and History/English class (which I abhored). The difference between the two was obvious to me (in my mind). In Math, you could easily know you had the right answer because you could check it. History? Good luck. (I once scored 4 out of 50 on a scan-tron history test – yeah, 4 out of 50). In fact, in History we were even allowed to argue with the teacher about the accuracy of the test (which, in the end only gained me 2-3 points on my miserable score).
Most programmers write code like it’s History.
Don’t believe me? What’s x in 5x = 15? Well, if we do the algebra we come up with 3 – but how can we be sure it’s 3? We test! If we put 3 in for x, we come up with 15. Great, so we got the answer right – and we know it’s right. (If I wanted to be really cute about this example, our test ”= 15” is already written for us.)
We can take this example a bit further to programming. Think about all the assumptions you make when you sit down to write code. In the process of programming a project, you’re likely to make thousands of assumptions each time you code. Things like “this will never be nil” or “this will always create a record.” All those little assumptions should first be written down in your tests so they fail. Not only does this help you keep track of your assumptions and make sure they are always valid, it also helps maintain a todo list for all those things you “plan to get to later” and never do. Interruptions have to be a major cause of bugs.
Not only are the assumptions fresh in your mind when you test first, all the cases are as well. It’s usually not so easy as 5x = 15, there’s usually a lot more scenarios you need to consider. Sure enough, when testing first it’s significantly easier to consider and record those cases (especially edge cases) as tests, then make sure they all pass now and forever.
So test first, it’s better than History.
Leave a Reply