A few weeks ago I attended a software event organized by the dutch Software Developer Network SDN. This time I followed a few sessions about Test Driven Development presented by (among others) Alex Thissen, Thomas Huijer and Dennis Doomen.
I must admit that before this sessions I was convinced that automated unit testing was a plus, but it would take just too much time (at least that is what I thought) so that I never actually used it. Triggered by this sessions I started to explore TDD and slowly but surely I am convinced by its pros.
So what is it?
TDD is not strictly about testing, but it is a software design method build upon testing. Check the TDD wiki for all the details, but basically it drills down to the following:
Every new feature in an application starts with building a test around one unit of code (a method or property), because of the fact that the real feature is not yet written that test will fail. After making the test you write the actual method which correctness can be checked by running the test.
Kind of strange huh? First test, then code. But when you think about it a little more it is a great way to improve your code quality.
Consider the following:
- By building a test you are triggered to think more about the specifications, heck by building the test you 'persist' the specifications in your code. (If specification changes, the test changes)
- It doesn't matter who writes the actual method, as long as the test fails he/she did not comply to the specifications.
- New features and specifications, which leads to refactoring your code, will be checked against your tests. If the test passes you will be fine.
In fact in TDD you will first change/refactor your test before refactoring the real code.
- You will try to keep test as small as possible, thus making smaller methods in your applications, thus making it less complex.
Less complex means more maintainable in the future. (Less time/costs)
“I don't care how good you think your design is. If I can't walk in and write a test for an arbitrary method of yours in five minutes its not as good as you think it is, and whether you know it or not, you're paying a price for it.”
Michael Feathers
Testing in Visual Studio
Visual Studio 2008 now offers unit testing. You can add a test project in your solution that refers your application/code library.
Making a first TDD application
Suppose we have some class Calculator with methods like Add, Divide etcetera.
Step 1
Create two test methods for the Add and Divide methods. A test method's result is stated by either an Assert, or an expected Exception:
[TestMethod]
public void Add()
{
int Int1 = 2;
int Int2 = 3;
int Result = calculator.Add(Int1, Int2);
Assert.AreEqual(5, Result);
}
[TestMethod]
public void Divide()
{
int Int1 = 6;
int Int2 = 3;
double Result = calculator.Divide(Int1, Int2);
Assert.AreEqual(2, Result);
}
[TestMethod]
[ExpectedException(typeof(DivideByZeroException))]
public void DivideByZero()
{
int Int1 = 6;
int Int2 = 0;
double Result = calculator.Divide(Int1, Int2);
}
In the test unit we created our Calculator class which we will test. Of course without the actual code this will not compile, so we create the initial method stubs, which will throw a not implemented exception.
Step 2
Run the tests. No supprise they will fail.
Step 3
Write the real methods:
public int Add(int Int1, int Int2)
{
return Int1 + Int2;
}
public double Divide(int Int1, int Int2)
{
return Int1 / Int2;
}
}
Step 4
Run the test. They succeed! Because the not so well choosen parameter names you could easily mismatch them in the method Divide, but your test will check for that!
What is next?
This example is rather simple. Complex codes, with for example database interaction will require some more coding for which you will write fakes and mocks. I will explore them in another post.
Conclusion
Although you might think that Test Driven Development takes a lot time in the process I am convinced (now) that it will pay back further on in the development process. Beside that it will boost the quality of your code and give you a base to safely refactor it in the future.
The examples where build in C#. I am not sure if this works in Delphi Prism as well, but I expect that it does.