Unit testing classes that require a message pump

Our push toward Continuous Integration, Test Driven Development and overall code quality here at OpenNETCF is a continuous learning experience.  One of the issues for unit/integration tests we’ve run into is that many SDF classes require an application message pump in order to “operate” properly.  A classic case it the FileSystemWatcher (FSW).  The FSW handles all of its eventing using the underlying OS architecture, which in turn uses windows messages (wouldn’t have been my choice, but hey, I didn’t architect it).

Well for windows messages to get dispatched, you need a message pump.  In a normal application, this is set up for you when you call Application.Run but in a unit test there isn’t such a call, and MSTEST certainly doesn’t spin up a pump for you.  We also don’t really want to create a Form just for our test (Application.Run requires a Form instance be passed in) and Application.Run blocks until the Form is closed so how wopuld we run our test and the pump anyway?

The solution I came up with is to use the OpenNETCF.Windows.Forms.Application2.Run method, which doesn’t require a Form, and to spawn it in a background thread at the start of the test, then at the end of the test call Application2.Exit, something like this:



      ThreadPool.QueueUserWorkItem(delegate(object o)
        {
          OpenNETCF.Windows.Forms.Application2.Run();
        });

      // run test here

      OpenNETCF.Windows.Forms.Application2.Exit();

Of course just having a Pump doesn’t necessarily mean that your messages will be dispatched when you want, and keep in mind that Windows messages are very low priority, so they might not get posted or dispatched immediately, so that adds more complexty to the test.  After you perform an action that causes a message (like creating a file) you want to call Application2.DoEvents to force messages to be dispatched, and you probably want to do it a few times after having your thread yield to make sure that the scheduler actually gets around to posting the things to the queue in the first place.

In the end it all works, it’s just not near as clean as one would hope for in a unit test.  Here’s an example of an FSW test from our production system:



AutoResetEvent m_testEvent = new AutoResetEvent(false);

[TestMethod()]
public void FileSystemWatcherCreatedWatchDirEventTestPositive()
{
  ThreadPool.QueueUserWorkItem(delegate(object o)
    {
      OpenNETCF.Windows.Forms.Application2.Run();
    });

  FileSystemWatcher fsw = null;
 
  string filename = "\Temp\Test.txt";
  if (File.Exists(filename)) File.Delete(filename);

  try
  {
    fsw = new FileSystemWatcher("\Temp", "*.*");
    fsw.Created += new FileSystemEventHandler(fsw_Created);
    fsw.EnableRaisingEvents = true;

    m_testEvent.Reset();

    File.CreateText(filename).Close();
    // give time for the message to get queued, and flush the queue a few times
    for (int i = 0; i < 10; i++)
    {
      Thread.Sleep(20);
      OpenNETCF.Windows.Forms.Application2.DoEvents();
    }

    // check for an event
    Assert.IsTrue(m_testEvent.WaitOne(1000, false), "Create Event did not fire");
  }
  finally
  {
    // clean up
    OpenNETCF.Windows.Forms.Application2.Exit();
    File.Delete("\Test.txt");
    if( fsw != null) fsw.Dispose();
  }
}

void fsw_Created(object sender, FileSystemEventArgs e)
{
  m_testEvent.Set();
}

1 thought on “Unit testing classes that require a message pump”

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