It’s not long after swallowing the unit testing pill that your appreciation for the colour green starts to increase. It soon reaches the point where you want a pretty little green light for every method. However, when you set out to test as much as you can you quickly run into some awkward issues.
For instance, during a unit test it would be nice if the concept of a disk kind of just went away. It’d be even better if running the PayPal tests didn’t cost 10p each time they succeeded, not to mention having the test suite complete during the same calendar month it was started.
Mocking
When building a decoupled system you end up creating lots of separate units. At some stage these separate units are put together in order to create more complex things, like for instance a UserService that depends on a UserRepository and an AccountService to function.
Dependencies have their own unit tests, which means that when we’re writing unit tests for the UserService we don’t need to worry about the UserRepository or the AccountService. If we could somehow tell these dependencies to behave like they usually do but without actually doing anything, we could prevent PayPal from charging us, data actually being put into the database and hour long waits during testing.
At this point, you’re no doubt scratching the word mocking into your desk with a sharp knife that you may use in other ways if I don’t just get to the point. And you’d be right, mocks rock. Mocking allows us to create stand-in dependencies that act like the real thing without doing any of the stuff we don’t care about; and laugh at silly people.
For example, we might create a mock instance of the UserRepository and have it always return a fake user from memory, rather than going all the way to the database and looking for actual data that in most cases will have been removed by someone else running their Can_Delete_A_User test.
The Perils of Mocking
What the hell has this got to do with moles? Don’t worry, I’m getting there. While mocks rock, you sometimes find yourself in situations where mocking seems like overkill.
For example, you might have a FileWriter that internally uses System.IO.File to create the physical file. While testing, you don’t want the FileWriter to use the real System.IO.File (for the reasons mentioned above) so you decide to mock it. You soon realise that things like System.IO.File and System.DateTime are not easily mocked because they don’t have their own interfaces.
In a stroke of pure genius you decide to create a new class and associated interface that wraps your use of System.IO.File. Awesome, now you can use this class instead of using System.IO.File directly. But now you also need to change the FileWriter to support dependency injection so that you can replace the instance of your class with a mock instance during the test.
This is the most common approach and it certainly works, but it becomes tedious when you have to wrap lots of things that should have been testable to begin with. Ultimately you make slight modifications to your architecture and introduce code that exists purely to make your code more easily testable.
Let’s look at some real contrived code to see this more clearly.
The Return of Rufus
Did I ever tell you about Rufus? Well, after his huge success at Big Heads Inc he went on to work for a bank where he was put in charge of creating their new banking system. The bank decided to hire Rufus when he was personally recommended by the CEO’s own Grandma. In recent months the bank has had a lot of bad press for multiple occasions where their customers have had 10p taken from their accounts, coincidentally around the same time the CI server is scheduled to do the build. Very strange indeed.
Rufus decides that he’s going to start with a BankService that will just allow withdrawals for now. The withdrawal will be handled by a WithdrawalService that the BankService will depend on. The BankService will have a single Withdraw method that returns the amount withdrawn if it’s successful or 0 otherwise.
public class BankService
{
WithdrawalService withdrawalService = new WithdrawalService();
public int Withdraw(int amount)
{
if (withdrawalService.Withdraw(amount))
{
return amount;
}
return 0;
}
}
As you’ve immediately noticed, the BankService has a concrete dependency on the WithdrawalService that is going to prevent us from easily mocking it. Rufus notices that the following test is not going to improve their current bad press situation.
[TestMethod]
public void Can_Withdraw_From_Account()
{
var bankService = new BankService();
Assert.AreEqual(bankService.Withdraw(10), 10);
}
When an instance of the BankService is created, it is going to create and use the real WithdrawalService whether we like it or not. To resolve this issue, Rufus predictably creates an IWithdrawalService interface and modifies the BankService to receive the dependency through constructor injection.
public class BankService
{
IWithdrawalService withdrawalService = null;
public BankService(IWithdrawalService withdrawalService)
{
this.withdrawalService = withdrawalService;
}
public int Withdraw(int amount)
{
if (withdrawalService.Withdraw(amount))
{
return amount;
}
return 0;
}
}
Now when Rufus comes to write a test that isn’t going to incite death threats, he can decide to use a different IWithdrawalService for the purpose of the test. Because Rufus rocks, he uses Moq for creating the mock instance of the IWithdrawalService.
[TestMethod]
public void Can_Withdraw_From_Account_Without_Death_Threats()
{
var withdrawalService = new Mock<IWithdrawalService>();
withdrawalService.Setup(x => x.Withdraw(It.IsAny<int>())).Returns(true);
var bankService = new BankService(withdrawalService.Object);
Assert.AreEqual(bankService.Withdraw(10), 10);
}
Moq makes Rufus look good! He’s now created an imposter version of the IWithdrawalService that simply returns true whenever the Withdraw method is called. Since the WithdrawalService has its own unit tests, all we need it to do is shut up and act normal.
Meet Jimmy
What the *hell* has this got to do with moles? Ah yes, the moles. Well, it turns out that Rufus has decided that there will only ever be one WithdrawalService and the BankService will always use the same one; the BankService will never work with any other type of WithdrawalService by design.
The dependency injection changes in the BankService are no longer buying Rufus anything and he concludes that they exist solely for the purpose of testing, as does the IWithdrawalService interface. Given the new constraints of the BankService (the fact it won’t be using any other type of WithdrawalService – come on, keep up) the first version now seems simpler and less convoluted.
But if Rufus goes back to the first version of the BankService, how can he mock the dependency on WithdrawalService when the tests are running? At this point, you’re no doubt scratching the word Typemock into your desk with a sharp knife that you may use in other ways if I don’t just get to the point.
Well, imagine instead that Rufus knows a little mole called Jimmy. Yeah, a mole. Jimmy is really good at digging (it’s innate) and he can dig into almost anything, particularly .NET assemblies. Well imagine that Rufus trains Jimmy to be ready for when the unit tests run, and when they do to dig into the assembly and change things around. Jimmy could quite easily dig into the WithdrawalService and make the Withdraw method return true.
This way, Rufus doesn’t need to change the BankService into a confident, dependency-injected stud just so it can be easily mocked; it can remain a skinny, shy but refreshingly simple nerd where the testing concerns are dealt with by Jimmy himself.
Microsoft Moles
Jimmy is of the Microsoft Moles variety. As part of Microsoft Research’s Pex project, we now have Moles. Moles lets us create a mirror image of any assembly and then redefine behaviour of anything inside the assembly via delegates. Then, by setting the HostType attribute on the test method we can signal that it should be run in an environment where the moled types are used instead of the real ones, allowing us to redefine behaviour in a class without having to manually modify the class at all.
Suddenly we can have DateTime.Now always return a particular value and have File.Exists return true without having to make sure a real file exists on a physical disk – all without having to sell your soul to the wrapper classes devil.
Rufus decides to revert the BankService back to the original slender version.
public class BankService
{
WithdrawalService withdrawalService = new WithdrawalService();
public int Withdraw(int amount)
{
if (withdrawalService.Withdraw(amount))
{
return amount;
}
return 0;
}
}
In order to use Moles, Rufus first downloads and installs the Moles package from Microsoft Research. He then defines which assemblies are to be moled by adding a .moles file to the test project. The .moles file is just an XML file which identifies each assembly that should be dug into and moled.
<?xml version="1.0" encoding="utf-8" ?>
<Moles xmlns="http://schemas.microsoft.com/moles/2010/">
<Assembly Name="Bank" />
</Moles>
Rufus has specified that the assembly named Bank should be moled, causing a Bank.Moles assembly to be produced automatically. He can now modify the original unit test, overriding the behaviour of the WithdrawalService without ever creating a mock instance manually.
[assembly: MoledType(typeof(WithdrawalService))]
[TestMethod]
[HostType("Moles")]
public void Can_Withdraw_From_Account()
{
MWithdrawalService.AllInstances.WithdrawInt32 = (obj, amount) => true;
var bankService = new BankService();
Assert.AreEqual(bankService.Withdraw(10), 10);
}
When using Moles, we need to mark the assembly with the MoledType attribute to configure which types should have their moled type used over their original type. This is done on line 1 where we indicate that any instance of WithdrawalService should use the moled type instead.
The only changes from the original unit test are those on lines 4 and 7. Line 4 ensures that when the test is run, it’s done so within the Moles environment. Line 7 uses a delegate to specify new behaviour for the Withdraw method, making it simply return true in all cases.
Earlier, when I said “Moles lets us create a mirror image of any assembly” I actually lulled you into a false sense of security – kind of. The assembly created by Moles isn’t exactly a mirror. For instance, methods/properties are prefixed with an ‘M’ and are named to reflect the parameters they have or the type of property they are. This is why the moled Withdraw method is actually called WithdrawInt32.
Methods of the moled assembly can be assigned delegates that define their new behaviour. In this example, the WithdrawInt32 method is expecting a Func<WithdrawalService, int, bool>. The additional WithdrawalService parameter is because we are defining the behaviour of all instances, so Moles will pass along the particular instance in case it’s needed.
The End
Rufus has used Moles to ensure that when the Withdraw method of any instance of a WithdrawalService is called it simply returns true, which is exactly what was achieved with the previous version of the test that used mocking.
Given the decision that the BankService was never to use other types of WithdrawalService, the use of Moles has saved Rufus from having to modify the BankService to support dependency injection and introduce a new interface purely for the sake of testing.
In a lot of cases your classes will be designed to support dependency injection, making mocking a perfectly suitable choice for creating test doubles. In addition, most modern mocking frameworks offer much more than simply replacing behaviour. However, in some situations it’s useful not having to modify code for the sake of making testing easier and Moles helps greatly when doing this.
Wait, What Happened to Rufus?
Rufus became even more loved (if that’s possible) by the elderly female customers of the bank as soon as the test suite stopped charging them each time it ran – leaving more cash for them to spend on new Head Effects mutations. Rufus and Jimmy went on to conquer many more mocks. They both live on to be subjects of another story.