Unit Testing Legacy Code With C# 3.0 Language Features
We all have some old legacy code from the C# 2.0 days floating around--Legacy in the Feathers sense of the word that there are no unit tests around it. We also know that we eventually need to get some tests around that old code just to nail it down. Did you know that you can test C# 2.0 source code from C# 3.0 assemblies? It seems incredibly obvious in hindsight but it had never even occurred to me until Patrice Beavuis was kind enough to point it out during an email conversation on unit testing a few months ago. Why would you want to do this? Because with C# 3.0 you can take advantage of more modern testing and mocking frameworks like Moq.
Take this bit of "legacy code", for example...
public class AccountManager
{
private readonly IInterestService _interestService;
public AccountManager(IInterestService interestService)
{
_interestService = interestService;
}
public void TransferFunds(double amount, Account sourceAccount, Account destinationAccount)
{
sourceAccount.Withdraw(amount);
destinationAccount.Deposit(amount);
}
public void AddInterest(Account account)
{
account.Deposit(account.Balance * _interestService.CurrentInterestRate);
}
}
The AccountManager class is a standard C# 2.0 class designed to do everything a bank could do. That is, it can transfer money between accounts and it can add interest to accounts. This is a nice little class and does everything it should...we think. We can only assume it does everything we need it to because there are no unit tests. However, we wrote this class 2 years ago and have since transitioned to Visual Studio 2008 and the wonderful world of C# 3.0.
Let's imagine that we need a test to verify that we can transfer money between two accounts. Sure we can write a unit test to verify this with C# 2.0 technologies, but just because the class under test is 2.0 doesn't mean our tests have to be. Let's use Moq and fully exploit our 3.0 technologies...
[Fact]
public void Accounts_can_accrue_interest()
{
var account = new Account(50.0);
var interestServiceMock = new Mock<IInterestService>();
interestServiceMock.Expect(service => service.CurrentInterestRate).Returns(0.10);
var manager = new AccountManager(interestServiceMock.Object);
manager.AddInterest(account);
Assert.Equal(55.0, account.Balance);
}
Notice the use of the lambda expression to set the expectation on
the mocked instance of IInterestService. Because we're using a C# 3.0
class library to test our code we can take full advantage of these
features, even though our class under test was created with C# 2.0!
You can download the sample from here.
Remember, just because your legacy code is using an old technology doesn't mean your tests have to!
Jeremy Jarrell is a software developer practicing in the Pittsburgh, PA market. He specializes in desktop application development with the .NET platform. He is heavily involved in the .NET developer community both as a regular contributor to open source and as a frequent presenter at user groups throughout both the Pittsburgh and Philadelphia area. His interests currently include client application technologies, developer productivity, and leading edge development techniques such as test-driven development. He is currently employed by Matrix Solutions of Pittsburgh, PA, the leading provider of strategic account analysis and CRM software to the media industry. He currently resides in northern West Virginia, with his wife, Mary, their two cats, three goldfish—all named for sushi dishes—and a 2 lb. hyper-active miniature dachshund. He can be reached through his website at www.JeremyJarrell.com. Jeremy is a DZone MVB and is not an employee of DZone and has posted 2 posts at DZone.
- Login or register to post comments
- 956 reads
- Printer-friendly version
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)














