如何为使用Application.Current.Dispatcher.Invoke的方法编写WPF异步单元测试?

时间:2018-11-13 13:49:11

标签: c# wpf multithreading mstest dispatcher

我们有一个用WPF编写的应用程序。 我正在尝试为在后台线程上运行的某些代码编写单元测试。在此代码中的某些地方,我们需要在UI线程上执行操作。在那些地方,我们使用以下代码结构:

Application.Current.Dispatcher.Invoke(new Action(() =>
{
// do something on UI thread
}));

当我创建异步单元测试时,它似乎卡在了Invoke方法上。我猜这是因为调度程序不是“调度”。我试图通过使用称为DisaptcherUtil的类来解决此问题,该类在互联网上的许多地方都被引用了。但是我无法使它正常工作。我的代码的简化版本现在看起来像这样:

    [TestMethod]
    public async Task TestDispatcher()
    {
        new Application();

        DispatcherUtil.DoEvents();

        await Task.Run(() => MethodUsingDispatcher());
    }


    private void MethodUsingDispatcher()
    {
        Application.Current.Dispatcher.Invoke(new Action(() =>
        {
            Console.WriteLine("On the dispatchee thread!");
        }));

        Console.WriteLine("BAck to background trhead");
    }

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

        private static object ExitFrame(object frame)
        {
            Console.WriteLine("ExitFrame");

            ((DispatcherFrame)frame).Continue = false;
            return null;
        }
    }

当我运行名为“ TestDispatcher”的测试时,它将挂起。

任何人都知道为什么会这样吗?这是执行此操作的正确方法,还是应该改走为我可以在测试中模拟的Dispatcher创建接口的路线。我已经在某些地方看到了这一点。

1 个答案:

答案 0 :(得分:2)

我想说的是,您应该将调度隐藏在接口后面,并在单元测试中对其进行模拟:

interface IDispatcher
{
    void Dispatch(Action action);
}

您可以在测试中轻松模拟这一点,并期待那些已调度的呼叫。

使用真正的调度程序并且可以由您的应用程序使用的实现:

public class Dispatcher 
{
    public void Dispatch(Action action)
    {
        Application.Current.Dispatcher.Invoke(action);
    }
}