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”);

    }

}

 
There are a few more tests (null name etc) that need to be coded. This solution is good enough for our customer and the application is released.
 

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(“”);
}

This test fails, of course. One way to solve this problem is to use an if statement and a property to control the output mechanism.
 

Part 3 - First Solution, inline-condition

 
Listing 6 - first solution

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”);

    }

}

 

 
Lets refactor this. The Console/MessageBox decision needs to be performed in many places. Lets extract a class Message to do this for us.
 

Part 4 - Extract the Message Class

Listing 7 - 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?

Bookmark at:
Add 'Dependency Injection with TypeMock' to Del.icio.us Add 'Dependency Injection with TypeMock' to digg Add 'Dependency Injection with TypeMock' to reddit Add 'Dependency Injection with TypeMock' to Feed Me Links! Add 'Dependency Injection with TypeMock' to Technorati Add 'Dependency Injection with TypeMock' to Yahoo My Web Add 'Dependency Injection with TypeMock' to Newsvine Add 'Dependency Injection with TypeMock' to FURL Add 'Dependency Injection with TypeMock' to blinklist Add 'Dependency Injection with TypeMock' to My-Tuts 

13 December 2007 | TDD, .NET Tests | Comments | Print This Post

2 Responses to “Dependency Injection with TypeMock”

  1. 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. 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

Leave a Reply

  1.  
  2.  
  3.  
Search Eli Lopian’s Blog (TypeMock)

Navigation

Recent Posts

Categories

Archives

Managment