Unit testing a MessageBox.Show

I have an extension method that does a .ToMessageBox(..). As you might imagine, when I try to test this with a unit test, it pops up a message box and hangs the unit test framework until I click OK. This is not very ideal. However, I want to be able to unit test this and it’s convenience overloads.

If you look at the MessageBox class, it does not implement any interfaces nor does it inherit from any base class. Worse, it has no constructors so I can’t inherit from it either.

From searching around, I saw a reference to someone getting around this with a dependency property – in a very confusing way. However, it got me thinking that I might get around this problem with delegates. This bent my brain at first, but now it seems so obvious!

The plan is this: I create a delegate that matches the signature of the specific implementation of MessageBox.Show that I need. Then, at run-time, I can point that delegate at the real MessageBox.Show, or to a mock/non-UI method that I control in my unit tests.

This might be kind of confusing. Picture this, instead of pointing to MessageBox.Show(..), I am going to define a signature that matches that call – that’s a delegate. That then allows me to point that “function pointer” to either the real Message>Show(..) because the signature matches, or I could point it to a mock one that I create.

Here is some code:

The Actual Code That Uses The MessageBox:

   1: /// <summary>

   2: /// Language extensions for <see cref="TimeSpan"/>.

   3: /// </summary>

   4: /// <threadsafety static="true" />

   5: public static class TimeSpanExtensions

   6: {

   7:     static TimeSpanExtensions()

   8:     {

   9:         CurrentMessageBoxShow = MessageBox.Show;

  10:     }

  11:  

  12:     public delegate DialogResult MessageBoxShow(string text, string caption, 

  13:         MessageBoxButtons buttons, MessageBoxIcon icon, 

  14:         MessageBoxDefaultButton defaultButton, MessageBoxOptions options);

  15:  

  16:     public static MessageBoxShow CurrentMessageBoxShow { get; set; }

  17:  

  18:     public static void ToMessageBox(this TimeSpan timeSpan, String message)

  19:     {

  20:         StringBuilder output = new StringBuilder();

  21:  

  22:         output.Append(timeSpan.ToString()).Append(" - ").Append(message);

  23:  

  24:         CurrentMessageBoxShow(output.ToString(), 

  25:             Properties.Resources.TimespanExtensionMessageBoxTitle, 

  26:             MessageBoxButtons.OK, MessageBoxIcon.Information, 

  27:             MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);

  28:     }

  29: }

On like 24, I was calling MessageBox.Show(..) – but now I’m invoking the delegate instead.

By default, as provided in the static constructor on line 9, this delegate points to the REAL MessageBox.Show. However, I expose that delegate out as a property of CurrentMessageBoxShow. So, in my unit tests, I can override this with my own implementation and this ToMessageBox(..) method will be none the wiser:

Unit Test:

   1: [TestMethod]

   2: public void ToMessageBoxWithValidStringArgumentsTest()

   3: {

   4:     // Arrange

   5:     TimeSpan timeSpan = new TimeSpan(1);

   6:     DateTime nowDate = DateTime.Now;

   7:     Boolean wasShown = false;

   8:  

   9:     TimeSpanExtensions.CurrentMessageBoxShow =

  10:         new TimeSpanExtensions.MessageBoxShow((text, caption, buttons, 

  11:             icon, defaultButton, options) =>

  12:         {

  13:             wasShown = true;

  14:             return DialogResult.OK;

  15:         });

  16:  

  17:  

  18:     // Act

  19:     TimeSpanExtensions.ToMessageBox(timeSpan, "My Message");

  20:  

  21:     // Assert - no exceptions

  22:     Assert.IsTrue(wasShown);

  23: }

As you can see on line 9, I override the default CurrentMessageBox with my own anonymous delegate that simply sets a flag (line 13) and returns a DialogResult (line 14).

This approach let’s me fully test my code without having to actually invoke a real MessageBox.Show(..)!

If you are new to delegates, this is likely very confusing. However, if you dabble with delegates – this is a classic example of having the right tool for the job. Without using delegates, I literally cannot think of any other way that I could unit test this code without popping up an actual messagebox. When the original implementation left me with my hands tied, there were no other alternatives.

Anyhow, hopefully this helps – this idea could prove to be very useful when trying to unit test against anything that uses external resources, but where there is no interface, common base class, and when the implementation is sealed.

Posted in .NET 3.5, .NET 4.0, Best-practices, DI and IOC, Uncategorized, Unit Testing, WinForms

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Archives
Categories

Enter your email address to follow this blog and receive notifications of new posts by email.

Join 5 other followers

%d bloggers like this: