Content

Showing posts with label dispatcher. Show all posts
Showing posts with label dispatcher. Show all posts

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