Correct method for using the WPF Dispatcher in unit tests

Since the dispatcher is problematic in unit tests, my solution would be to break your view-model's dependency on the dispatcher. I assume that currently you have hard coded references like:

Dispatcher.CurrentDispatcher.BeginInvoke(..

The dispatcher is an external dependency and shouldn't be part of your unit tests - we can assume the dispatcher works.

I would use dependency injection (either poor mans, Unity, etc). Create a suitable interface representing the dispatcher. Create a real implementation which wraps the real dispatcher. Create a fake implementation which uses Action.BeginInvoke. In the fake you record all IAsyncResults returned to calls to BeginInvoke.
Then have a helper method which would wait for all calls to completed which you can use in your test to wait for completion.

Or have a view model base class which does the same thing. Calls the dispatcher normally but can be directed to call a fake during tests.


I found an easy solution. Instead of processing the Frames Async in the Dispatcher, I added a synced method to the DispatcherUtil class. Calling this DoEventsSync()-method returns when all Frames were processed, i think this should help here:

    public static class DispatcherUtil
    {
        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public static void DoEvents()
        {
            var frame = new DispatcherFrame();
            Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
                new DispatcherOperationCallback(ExitFrame), frame);
            Dispatcher.PushFrame(frame);
        }

        public static void DoEventsSync()
        {
            var frame = new DispatcherFrame();
            Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background,
                new DispatcherOperationCallback(ExitFrame), frame);
            Dispatcher.PushFrame(frame);
        }

        private static object ExitFrame(object frame)
        {
            ((DispatcherFrame)frame).Continue = false;
            return null;
        }
    }

Now simply use DispatcherUtil.DoEventsSync(); instead of DispatcherUtil.DoEvents(); in the Unit-Tests. You can be sure the Dispatcher processed everything, before the Unit-Tests continue. No callbacks need to be added for tests.

The confusing part is that DispatcherUtil.DoEvents(); really is a DispatcherUtil.DoEventsAsync(); because BeginInvoke(..) is an Async-Method