Dependency Injection with TypeMock
The has been some buzz about Dependency Injection lately (here is another thread). But I want to actually show how TDD with TypeMock can lead to a DI solution, and how the tests will step by step naturally lead to the DI solution when the business features require it.
Lets start with a very simple example that displays an error message in a Windows Message Box. This is a requirement from the customer, just to make things simple we have a ValidateThatNameIsOk() method that displays a Message when the Name is empty.
Part 1 - Initial Code
Listing 1 - the test.
[Test]
public void ValidateThatNameIsOk_Passes_WhenNameExists()
{
SomeApplication classUnderTest = new SomeApplication();
classUnderTest.ValidateThatNameIsOk(“r”);
}
Listing 2 - the simplest solution
public void ValidateThatNameIsOk(string name)
{
}
Now lets add a failing case (we must mock out the MessageBox or we will halt the test)
Listing 3 - another test.
[Test,VerifyMocks]
public void ValidateThatNameIsOk_Fails_WhenNameIsEmpty()
{
// Record Mocks
using (RecordExpectations recorder = RecorderManager.StartRecording())
{
MessageBox.Show(“A Name must be entered“);
recorder.Return(DialogResult.OK);
}
SomeApplication classUnderTest = new SomeApplication();
classUnderTest.ValidateThatNameIsOk(“”);
}
Listing 4 - and here is the simplest solution.
public void ValidateThatNameIsOk(string name)
{
if (name.Length==0)
{
MessageBox.Show(“A Name must be entered”);
}
}
Part 2 - More Features Request
Our application is a success and we managed to deliver on time (because we didn’t write unneeded code). After some time our customer asked for a new feature: “run the application in batch mode”. Now we cannot use MessageBox.Show() any more. Now we need to write the message to the console (or a file).
Lets start with the test*.
Listing 5
[Test,VerifyMocks]
public void ValidateThatNameIsOk_FailsAndWritesToConsole_WhenNameIsEmpty()
{
// Record Mocks
using (RecordExpectations recorder = RecorderManager.StartRecording())
{
Console.WriteLine(“A Name must be entered”);
recorder.CheckArguments();
}
SomeApplication classUnderTest = new SomeApplication();
classUnderTest.ValidateThatNameIsOk(“”);
}
Part 3 - First Solution, inline-condition
private bool useConsole = false;
public bool UseConsole
{
set { useConsole = value; }
}
public void ValidateThatNameIsOk(string name)
{
if (name.Length==0)
{
if (useConsole)
Console.WriteLine(“A Name must be entered”);
else
MessageBox.Show(“A Name must be entered”);
}
}
Part 4 - Extract the Message Class
public class Message
{
private static bool useConsole = false;
public static bool UseConsole
{
set { useConsole = value; }
}
public static void Show(string message)
{
if (useConsole)
Console.WriteLine(“A Name must be entered”);
else
MessageBox.Show(“A Name must be entered”);
}
}
and here is the validation method.
public void ValidateThatNameIsOk(string name)
{
if (name.Length==0)
{
Message.Show(“A Name must be entered”);
}
}
Our Console test (and the batch runner) will need to call Message.UseConsole = true and all our tests will pass.
Now we need to add a feature to write the message to an external file.
Part 5 - Add another output stream and Polymorphism
To add another output stream (a log file for example), we would write a test which will lead to a change in the Message class, the simplest way is to change the boolean to an enumerator and change the if statement to a switch,
private static MessengerType messenger = MessengerType.MessageBox;
public static MessengerType Messenger
{
set { messenger = value; }
}
public static void Show(string message)
{
switch (messenger)
{
case MessengerType.MessageBox:
MessageBox.Show(message);
break;
case MessengerType.Console:
Console.WriteLine(message);
break;
case MessengerType.File:
File.AppendText(message);
break;
}
}
which will lead to a refactor to use polymorphism.
Listing 8 - Using Polymorphism
public interface IMessage
{
void Show(string message);
}
public class MessageBoxMessage : IMessage
{
public void Show(string message)
{
MessageBox.Show(message);
}
}
public class ConsoleMessage : IMessage
{
public void Show(string message)
{
Console.WriteLine(message);
}
}
And the Message class
public class Message
{
private static IMessage messenger = new MessageBoxMessage();
public static IMessage Messenger
{
set { messenger = value; }
}
public static void Show(string message)
{
messenger.Show(“A Name must be entered”);
}
}
Take a look at the code. We have reached the Dependency Injection pattern. Here is how we inject the correct messenger.
Message.Messenger = new ConsoleMessage();
At this point all our tests still pass without any change
Conclusion
We have seen that using TDD and TypeMock, it is possible to build software that can handle change in an incremental manner. When a business need requires the Dependency Injection Pattern, refactor-ing the code will lead to the correct solution, without needing to design it up front. The tests won’t need to be rewritten and we follow the YAGNI principle.
*How do I manage to mock Console.WriteLine in mscorlib?
4 Responses to “Dependency Injection with TypeMock”
1 Alex Simkin 17 December 2007 @ 10:47 pm
It is not DI pattern, it is Strategy pattern. DI pattern requires externally configurable container.
2 Eli Lopian 17 December 2007 @ 11:23 pm
Alex,
Strictly speaking, you are correct (although DI never REQUIRES that you don’t have a default implementation, and that it is always and only externally configurable (http://en.wikipedia.org/wiki/Dependency_Injection).
In any case, I did leave out the last step of changing the messenger field to load it via Ioc.Get();
and to set the Ioc.Bind();
it is a really simple step once the team realizes that there is a need to configure the dependency externally
3 SuevescumTese 28 May 2009 @ 3:16 am
You guy’s heard it’s some accident happened in Mike Tyson family pure guy, his so great and popular , even he do a lot of crazy things he didn’t deserve it . I’m a big fan of his - we should pray for him.
4 Woulpurgego 18 December 2009 @ 10:22 pm
The famous buy Viagra (blue medicine) from Pfizer, it is a treatment for erectile dysfunction
Leave a Reply