Fixing Bugs in Legacy Code
Sometimes we have to fix a bug in code that was not developed using TDD and has no tests.
What I do this is to use one of the main principles of TDD and start with a failing test.
This failing test should replicate the bug report.
Then when you fix the code, the test should pass.
Sometimes when looking at an ‘old’ piece of code in can be tempting just to try and fix it.
But make the effort of adding a testing framework and the first test. You and your colleagues will benefit in the long run.
The code will gradually become more stable and more maintainable.
This principle can also be used when adding new functionality to an existing application that was developed without TDD.
Showing posts with label TDD. Show all posts
Showing posts with label TDD. Show all posts
Saturday, 19 September 2009
TDD Spawns a Guardian Angel
OK We all know that TDD is a technique for DESIGNING your code.
One of the massive side effects of TDD is that you end up with a set of tests that should give nearly 100% coverage of your code.
This set of tests is what I refer to as your Guardian Angel. The effects of having this set of tests constantly looking over your shoulder is immense. Especially if a project reaches a panic stage where people are introducing late changes and new requirements. Being able to run hundreds of tests before doing a build and release is immeasurable.
The set of tests can also come to your rescue when someone says have “you got any design documentation”. Of course you have. The tests represent the most up to date design document that you can have. (Unlike separate documentation that can quickly become out of date.
So, have you got a Guardian Angel or a little devil on your shoulder?
One of the massive side effects of TDD is that you end up with a set of tests that should give nearly 100% coverage of your code.
This set of tests is what I refer to as your Guardian Angel. The effects of having this set of tests constantly looking over your shoulder is immense. Especially if a project reaches a panic stage where people are introducing late changes and new requirements. Being able to run hundreds of tests before doing a build and release is immeasurable.
The set of tests can also come to your rescue when someone says have “you got any design documentation”. Of course you have. The tests represent the most up to date design document that you can have. (Unlike separate documentation that can quickly become out of date.
So, have you got a Guardian Angel or a little devil on your shoulder?
Friday, 18 September 2009
TDD is a complete failure.
What I mean by that is when you design a method using TDD, you start with a failing test, and you then implement code to make the test pass.
The test defines your expectations of the code that you will be designing. When writing the test, think in terms of what a client or consumer would expect of the method.
Let me demonstrate. Imagine some sort of financial accounting system. We have a list of credits, money going into the account and a list of debits, money leaving the account.
For the sake of this demonstration, let's have the two sets of values in two arrays:
int[] credits = {23, 42, 117, 11, 48};
int[] debits = {93, 22, 38, 29, 14};
Our first test will look like this. (This is written in C#)
[TestMethod]
public void Calculate_CreditsGreaterThanDebits()
{
int[] credits = {23, 42, 117, 11, 48}; // Total: 241
int[] debits = {93, 22, 38, 29, 14}; // Total: 196
Account account = new Account();
int balance = account.Calculate(credits, debits);
// We expect the result to be 45, that’s (241 - 196)
// In TDD we can perform various checks using something called an assert.
// In this case, I just want to check that the balance is equal to 45.
Assert.AreEqual(45, balance);
// If the balance is anything other than 45, the test will fail.
}
public class Account
{
public int Calculate(int[] credits, int[]javascript:void(0) debits)
{
return 0;
}
}
Assert.AreEqual failed. Expected:<45>. Actual:<0>.
That's good news. In TDD we love a failing test. We can now do the enjoyable part of writing real code to make the test pass.
public class Account
{
public int Calculate(int[] credits, int[] debits)
{
int totalCredit = 0;
int totalDebit = 0;
foreach (int credit in credits)
totalCredit += credit;
foreach (int debit in debits)
totalDebit += debit;
return totalCredit - totalDebit;
}
}
Notice the name of the test, Calculate_CreditsGreaterThanDebits.
The first part, Calculate, indicates the target method that I am designing. The second part describes the scenario that I am designing for.
The name of the class that contains this test is AccountTests. This naming convention means that this test class will be used to design the methods in the Accounts class.
Having got this one scenario working, you then implement a few more scenarios such as:
Calculate_CreditsLessThanDebits()
Calculate_CreditsEqualToDebits()
Subscribe to:
Posts (Atom)