Friday, July 11, 2008

The Joys of Testing

Yes, you read it right. The title does say "The Joys of Testing". And no, I am not trying to be cute or imply anything other than what the title says. It actually can (and should) be a pleasure and joy to test your code.

When I first joined Google as a Software Engineer in Test, fresh out of college, all naive and innocent, I had a very limited exposure (read almost none) to testing. I wasn't even sure if I could do justice to my role there. But over the past year, I have sunk into my role with relish and learned far more about testing (and coding and engineering) than I seemed to have in my 4 years at college. This is not to say that I didn't learn anything at college, because I sure did, from Data Structures and Algorithms to OOPS to AI, but none of them ever seemed to cover or focus on testing.

And then I joined this industry where everyone I talk to generally says that you should test your code, and every class you write should be accompanied by tests. So I learnt JUnit and figured out what they meant. But then I started wondering, how many people actually mean "Do as I say, not as I do." when they say this. For I have seen code snippets of classmates where I go "What the heck was this guy thinking ?" . I have come to realize that many people just don't know how to write tests. Or understand the importance of the same. Oh sure, they say they have tests, and they do, but how many of the tests actually provide any value.

Testing done right is an art. A joy in itself to behold. I still feel shivers and goosebumps when I see a nice beautiful class which is nice and easy to test. There is actually something known as Design for Testability which I will cover in some of my later posts, but the importance of that is underrated. There are so many great tools and techniques to make testing easier which are often left unmentioned. I hope to cover a great many of those tools and approaches.

And we finally come to the question of "Why test ?". I mean, who cares if some code has tests or not. I can clearly see it is working. But to those, I raise this question. Say your mythical application which you see is working. Say you introduce a slew of changes to it, across various parts of the application. And then when you fire up your Oh so perfect application, its broken. Now you manually have to go over whatever you changed in your codebase to find out what broke it. If you had tests around your application, preferably unit tests, you wouldn't have had to wait to compile, build your application, and then go and check the various parts. Just hit a button (in say eclipse), and BAM!!! AssertionFailed. You know exactly what line your code is breaking at, and even why, if you have unit tested properly.

Unit tests when done right, provide multiple benefits, including the following :
  • Pin point breakages and causes of failures to the line level
  • Reduce the amount of manual testing you have to do for your application
  • Help you design your code beautifully (Design for testability)
  • Give you instant feedback on whether something works as intended
  • Quality Assurance metric for your code
  • Reduce the amount of code paths you have to test manually.
By the last point, consider the following case. Assume that each part of the app is a class, for ease of understanding. An app, whose frontend is a single class with a single method talks to this middle tier which has again, say one method, which does some things and finally talks to the back end layer, which has, you guessed it, one method. Now each method has 5 possible code paths through it. Now you have two options :
  1. You can manually test the whole app, which leaves you with 5 * 5 * 5 code paths to consider, which is 125 possible tests
  2. Or you can test each part individually with unit tests. Thats 5 unit tests for the frontend, 5 for the middle tier and 5 for the back end. And then you can have one large scale integration test which makes sure that everything's connected properly.
You just cut down from 125 manual tests to say 16-20 quick small tests which do the exact same thing. You know each individual piece works on its own, and you know that each part is connected properly to its neighbors. Thus, the whole application works.

In my next post, I intend to cover the most basic, fundamental technique to writing testable code, Dependency Injection. I will have a few Java based examples to give an idea, along with a few mentions of way to make it easier.


akuhn said...

You wrote:
>"Pin point breakages and causes of failures to the line level"

Caught my attention. Do you refer to "line of test code" or "line of app code"? If the latter, how do you achieve this? With common unit test, you get the failing line of test code not the failing line of app code. Or even worse, one buggy app line causes dozens or hundreds of test to fail. What is your experience to deal with this?

Gaurang said...

SO you do have time....