What is Unit Testing?
It is a method to drastically reduce the amount of errors in your source code. Let me explain: Traditionally, when you write a new method in one of your classes, you test it either by using it right away or sometimes by creating small console applications that call the new method with different arguments. The latter approach allows you to easily debug the method in isolation instead of having to carefully provoke the situations you want to test while running the game.
Unit Testing takes this latter idea one step further. Instead of writing throw-away console applications, you write small test methods that validate the correct behavior of a single method or class. These test methods are then kept for the lifetime of the application, so they can be run again at any time, ensuring that the code is still working whenever you change something.
Tests are written on the method level -- you don't write huge tests that take entire classes through thousands of different scenarios, but instead test method by method, seeing whether each one does the right thing with normal data, extreme values, borderline cases and whether it fails in a controlled manner if you provide it with invalid data.
So, in short, whenever you introduce new code to your game, unit testing will ensure that it really does exactly what you think it does. You can apply this concept to varying degrees and, in the most extreme case, require a unit test for any method in a given project. Programmers practicing test-driven development will start by writing a new unit test and only then try to write a method or class that passes the test.
Advantages of Unit Testing
Believe me, it's not half as tedious as it sounds, plus, there are lot more benefits to unit testing than just avoiding errors:
-
Applied at any level, unit testing leads to a large improvement in code quality.
With unit testing, programming is no longer like carefully crafting a fragile sculpture. It much more becomes a process of continuous refinement. Programmers in projects that apply unit testing don't need to fear that they might break something by improving existing code. In this sense, unit testing programmers are a lot like wikipedians -- if they know better, they just change it. They merely need to run the tests to see whether their new code is still producing the desired results.
-
Once discovered, you can get rid of bugs for good.
Whereas in normal projects, bugs can be reintroduced even after someone fixed them, in a unit tested project, before fixing the bug, a test can be written first that provokes the bug. Not only does it force you to exactly know under which circumstances the bug is occuring, it also tells you when the bug is really gone without any side effects. And leaving the test in place, you can be sure that the bug will not make it into a released version ever again.
-
Discover hard-to-find bugs with ease.
Because each method is tested in isolation, it's much easier to locate the source of failures. The more experience you get with writing good unit tests, the less often you'll find yourself debugging deeply nested function calls in hard-to-reproduce situations.
-
Validate that you're actually writing reusable code.
Unit Testing is a way of designing software just as much as it is about testing it. If you've got the habit of designing large, interwoven object models where your objects regularly go fishing for other objects they need to interact with, creating unit tests will force you to break this pattern and design for reusability, eg. telling objects which other objects they are supposed to work on instead (a design principle commonly known as "Tell, Don't Ask"). Don't worry, you can still test classes that are have to depend on other classes by simply "mocking" those other classes using frameworks like NMock.