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?

120 comments
  1. あなたの 変更|あなたはの思想とみなさ場合サイト | 好奇心の不思議私はでしたか?その非常によく書かれました。私はyouveは言うようになったものが大好きです。しかし、多分あなたは少しより多くのコンテンツのように、人々はそれとのより良い接続することができることができるように。または2 写真 |ホードは、1 1は持っていることのためのテキストの非常に多くを得ました。たぶん、あなたは宇宙、それをより良いだろうか?
    土日祝も発送 本物 レディース

  2. Then head to the settings tab which is the cog symbol.
    There are a number of choices here but you can simply utilize the
    options shown into the image to begin with.
    You might conserve the sniffed traffic to your facts as opposed to the phone’s interior memory.

    Feel free to visit my page wifi hacker iphone

  3. The processor or CPU will be the brains of the individual computer – it does most of the calculations your video game titles want to have to run (with the movie card undertaking most of the graphics function). With it finding such an critical part, you would instinctually go for the fastest – and most pricey – processor you could locate, but there is a improved alternate to blowing hard cash on one thing that will likely be obsolete in a year: receiving a processor that will play tomorrow’s video game titles at a low cost is the sweet spot for any gaming computer.
    http://noexcuselist.com/forum/discussion/279001/7ikx7b-longchamp-pliage-en-cuir

  4. В отличие от нашей державы в Германии проституция абсолютно легальна. как полагается оно иль отнюдь не мне размышлять.
    впрочем мне посчастливилось очутиться в некий из борделей. произошло оно в Кельне, в час странствия по Европе. Сначала я был просто поражен, мол так буквально последовать в бордель, уплатить денежки, и заняться любовью. Для себя оно что-то вроде полета на ночное светило. все-таки уже в самом лупанарие я понял, что тут относятся собственно к клиенту, а не так как путаны белокаменной. Всё сконцентрировано на то дабы потребитель оставил до фига бабок,телефоны проституток правда и интим услуги у них по высшему разряду. Кто будет в Германию зайдите в ихний бордель.

Add Comment

Required fields are marked *. Your email address will not be published.