Content

2/24/2012

Using the WPF Dispatcher in unit tests


I have got a problem in my current WPF project when unit testing with mstest.
In one of my ViewModels i need to use the dispatcher to set something in the view.
While Unit Testing this ViewModel i figured out theAction delegate will never covered.

Unit-Test with Dispatcher and BeginInvoke fails
  1.         [TestMethod()]
  2.         public void TestTheTest1()
  3.         {
  4.             bool myBoolean = false;
  5.             Action theAction = () => myBoolean = true;
  6.             Task.Factory.StartNew(() =>
  7.                 Dispatcher.CurrentDispatcher.BeginInvoke(
  8.                 DispatcherPriority.Normal,
  9.                 theAction));
  10.             Thread.Sleep(500);
  11.             Assert.IsTrue(myBoolean);
  12.         }        

The reason for this behavior is that the dispatcher is not processing any messages when called from the testrunner. A synchronous call (Invoke) still gets executed but no queued ones (BeginInvoke).

Unit-Test with Dispatcher and Invoke succeed
  1.         [TestMethod()]
  2.         public void TestTheTest2()
  3.         {
  4.             bool myBoolean = false;
  5.             Action theAction = () => myBoolean = true;
  6.             Task.Factory.StartNew(() =>
  7.                 Dispatcher.CurrentDispatcher.Invoke(
  8.                 DispatcherPriority.Normal,
  9.                 theAction));
  10.             Thread.Sleep(500);
  11.             Assert.IsTrue(myBoolean);
  12.         }

So i handled this by create a Dispatch helper class for myself. This class handle all Dispatcher calls at runtime and for unit-tests.

There are also other solutions to handle this problem.
You can trigger the processing of the messages manually with a DispatcherFrame.
The changed and working example looks like this:


Solution with DispatcherFrame
  1.         [TestMethod()]
  2.         public void TestTheTest3()
  3.         {
  4.             bool myBoolean = false;
  5.             DispatcherFrame frame = null;
  6.             Action theAction = () =>
  7.                 {
  8.                     myBoolean = true;
  9.                     frame.Continue = true;
  10.                 };
  11.             Task.Factory.StartNew(() =>
  12.                 {
  13.                     frame = new DispatcherFrame();
  14.                     Dispatcher.CurrentDispatcher.BeginInvoke(
  15.                         DispatcherPriority.Normal,
  16.                         theAction);
  17.                     Dispatcher.PushFrame(frame);
  18.                 });
  19.             Thread.Sleep(500);
  20.             Assert.IsTrue(myBoolean);
  21.         }

Also possible is to use a interface for the dispatcher and to have the posibility to mock the dispatcher.At runtime you can pulling in the interface from your IOC container.

Dispatcher interface
  1. public interface IDispatcher
  2. {
  3.     void Dispatch( Delegate method, params object[] args );
  4. }

2/01/2012

Tool tip of the day: NCrunch

This could be one of the things that you can't live without.

The usual steps you go with TDD and Visual Studio at the moment:
  • Write test
  • Stop and run tests
  • Write code
  • Stop and run tests
  • Refactor code
  • Stop and run tests

You can go with NCrunch and it look like:
  • Write test
  • Write code
  • Refactor code
NCrunch is an automated parallel continuous testing tool for Visual Studio .NET.
It intelligently takes responsibility for running automated tests so that you don't have to, and it gives you a huge amount of useful information about your tests (such as code coverage and performance metrics) inline in your IDE while you work.

I will give it a try with my current project.