Thursday, November 21, 2013

Unit Testing, Part 1

What is Unit Testing?

Here is the Wikipedia definition of unit testing. To me, unit testing is the use of code whose sole purpose in life is to test other code. Surely you've written a method in the past where you thought to yourself "Man, I feel for the poor tester who gets to test this project. How will they ever run through all 150 scenarios of this method?". I bet you've even written demo programs just to test your code libraries, which is a very similar concept to unit testing. It's code that tests code. Unit tests are generally coded as very simple pass/fail methods where there is no room for interpretation. The test passed or it did not.



Why Should I Do It?

Unit testing can help you as the coder to test your own code, thus ensuring higher quality. It can also be argued that unit testing saves you time, though that seems to be a matter of opinion. From some Google-fu the current prevailing opinion seems to be that in the long-run you will save yourself time by baking unit tests into your projects from the start. It should seem pretty obvious to you now that writing extra code up-front will take extra time up-front, so then the next leap of logic would mean that you save time further down the road, which I have seen myself. Picture a user reporting a bug that they just found out in the field. They have to take the time to call/email support, who researches, sends it over to the group that does the coding, it gets routed to a coder, you have to spend a while tracking it down until you eventually come up with the problem and possibly a solution. Now picture even 25% of those being found through unit tests that are created in the project before its release. Depending on where you look, you can find studies that state bugs found after release cost 15 or 20 times what it costs to find and fix a bug during development, so if you catch even 8% of potential bugs you've saved time in the long-run. Plus, less-buggy software means happier users and a support department which harbors less desire to strangle you in your sleep. One other reason I've found is more of a side effect, but I find that exercising my code through unit tests forces me to design code that has less rigid dependencies and is thus easier to maintain. This is something we'll get into more in a future post.

When Should I Do It?

We are delving more into my own personal opinion here, but I feel that unit testing should be used for *most* code written, whether it be a new development or maintenance/additions. Most importantly, if a bug is found you can usually create a unit test to ensure the bug never returns. This is one of the most helpful uses of unit tests I have found; it acts as a regression test so you and potentially other coders cannot reintroduce a bug into software once it has been fixed. There might be times where unit testing is not appropriate. I hate to say it, but I do believe that if you're in a super time crunch at work and your family doesn't recognize your face anymore, take shortcuts to keep your sanity and ditch the unit tests if you have to, but only if you absolutely have to! Your family has pictures of you after all. You also do not generally want to unit test code that does nothing but hit external resources (flat files, databases, web services, etc), but we'll get into that more in a future post.

I've Heard About Test Driven Development, What's That?
Test Driven Development, or TDD, is a development process whereby the code you write is tested by unit tests prior to the code functioning. It sounds odd but it goes like this (some people show more or fewer steps, but the concept remains):
1) Decide on a specific piece of functionality (chunk of code) you want to write.
2) Write a unit test to call this non-existent piece of code.
3) Compile the unit test; it fails because the code it's calling doesn't yet exist.
4) Create a shell for the piece of functionality; it's usually something as simple as an empty method.
5) Compile+run the unit test; it passes. However, your code doesn't do anything yet, so...
6) Have the unit check that the appropriate resulting condition has occurred.
7) Run the unit test again; it fails because the functional code does nothing yet.
8) Make your code do what it's supposed to do.
9) Run the unit test again; it should pass.
10) Create more unit tests for edge cases, different input, etc etc. Refactor code as necessary to get unit tests created/passed.

There are plenty of people on teh interwebs who will insult your grandmother if you don't zealously enforce TDD in your professional life, but I don't judge (well not about this anyways) so I won't fault you for not using it. Heck I don't use it. I tried it but I find all the bouncing back and forth between the test code and production code to be time-consuming and a little distracting. I work best if I write a small, focused piece of production code first and then test the pants off of it, but do what works best for you. Give TDD a shot and see if you like it. I did, and I don't :)

What's Next?

Well that depends on if you're a teacher's pet or if you like suspense. There's no middle ground here! You can research unit testing further on your own by looking at some of the links below or maybe try some Google-fu, you could try writing some unit tests on your own in your favorite language (it's easy I promise!), or you can wait for next week's blog where I'll show you some introductory unit testing in C#.

Resources

http://en.wikipedia.org/wiki/Unit_testing

http://superwebdeveloper.com/2009/11/25/the-incredible-rate-of-diminishing-returns-of-fixing-software-bugs/

http://en.wikipedia.org/wiki/Test-driven_development

1 comment:

  1. That first unit test is the hardest to write. Especially for folks who've never done it before. I wonder if a unit test newb could gain more comfort with unit testing by way of maintaining a project that already has the unit test scaffolding built in.

    The best time to fail is early!

    ReplyDelete