C# How to unit test Dispatcher

Dispatcher provides services for managing the queue of work items for a thread. Sometimes to execute a task on a background thread. 

Any task executed by calling Dispatcher.BeginInvoke(...) in unit test does not get executed until you do some wire-up.

This is how you would unit test code with Dispatcher.


using System;
using System.Windows.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
 
namespace UnitTesting.Tests
{
    [TestClass]
    public class DispatcherUtilTest
    {
        private ClassThatUsesDispatcher _subject;
        [TestInitialize]
        public void TestInitialize()
        {
            _subject = new ClassThatUsesDispatcher();
        }
 
        [TestMethod]
        public void UseDispatcher()
        {
            // Arrange
            var backgroundWorkDone = false;
            _subject.BackgroungWorkAction = () => { backgroundWorkDone = true; };
 
            // Act
            _subject.DoWork();
 
            // Assert
            // Without calling DispatcherUtil.DoEvents() the test will fail
            DispatcherUtil.DoEvents();
            Assert.IsTrue(backgroundWorkDone);
        }
 
        [TestMethod]
        public void DontUseDispatcher()
        {
            // Arrange
            var backgroundWorkDone = false;
            _subject.BackgroungWorkAction = () => { backgroundWorkDone = true; };
 
            // Act
            _subject.DoWork();
 
            // Assert
            Assert.IsFalse(backgroundWorkDone);
        }
    }
 
    internal class ClassThatUsesDispatcher
    {
        internal Action BackgroungWorkAction;
        readonly Dispatcher _dispatcher;
        internal ClassThatUsesDispatcher()
        {
             _dispatcher = Dispatcher.CurrentDispatcher;
             BackgroungWorkAction = DoSomeBackgroundWork;
        }
 
        public void DoWork()
        {
            _dispatcher.BeginInvoke(BackgroungWorkAction, DispatcherPriority.Background, new object[]{});
        }
 
        internal void DoSomeBackgroundWork()
        {
            // Make a web-service call
            // Read data from file-system
            // Wait for a resource
            // etc.
        }
    }
}


**** This is the class you would need to unit test Dispatcher ****

/// This class helps UnitTest Dispatcher.
/// Dispatcher does not automatically process its queue, 
/// DoEvents method here will tell the Dispatcher to process its queue


using System.Security.Permissions;
using System.Windows.Threading;
 
namespace UnitTesting
{
    public static class DispatcherUtil
    {
        [SecurityPermissionAttribute(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);
        }
 
        private static object ExitFrame(object frame)
        {
            ((DispatcherFrame) frame).Continue = false;
            return null;
        }
    }
}
   




Comments

Popular posts from this blog

WPF How to Dispose ViewModel when the associated UserControl (Not Window) closes?

WPF: How to Deep Copy WPF object (e.g. UIElement) ?