【问题标题】:Propagate exception thrown in continuation task when invoking dispatcher from unit test从单元测试调用调度程序时传播继续任务中引发的异常
【发布时间】:2014-01-21 21:31:00
【问题描述】:

我在单元测试中执行了以下代码:

        var continueScheduler = new CurrentThreadScheduler();
        var task = Task.Factory
            .StartNew(() => { })
            .ContinueWith(obj => { throw new Exception("Fail"); }, continueScheduler);

        while (!task.IsCompleted)
        {
            DoEvents();
            Thread.Sleep(10);
        }

StartNew() 启动一个执行空操作的新线程。然后CurrentThreadScheduler 确保在主线程上执行ContinueWith() 操作:

    public class CurrentThreadScheduler : TaskScheduler
    {
        private readonly Dispatcher _dispatcher;

        public CurrentThreadScheduler()
        {
            _dispatcher = Dispatcher.CurrentDispatcher;
        }

        protected override void QueueTask(Task task)
        {
            _dispatcher.BeginInvoke(new Func<bool>(() => TryExecuteTask(task)));
        }

        protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
        {
            return true;
        }

        protected override IEnumerable<Task> GetScheduledTasks()
        {
            return Enumerable.Empty<Task>();
        }
    }

while 循环等待任务(包括ContinueWith())完成。这是DoEvents() 代码:

    private 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;
    }

问题:

我希望ContinueWith() 操作中抛出的异常使测试失败。问题是CurrentThreadScheduler.QueueTask() 中的BeginInvoke() 吞下了异常,我无法找到检测它的方法。

我尝试订阅Dispatcher.CurrentDispatcher.UnhandledException,但从未调用过事件处理程序。我尝试使用Invoke() 而不是BeginInvoke(),希望异常能够传播,但没有成功。

不用说,这个问题中的代码是为了演示我的问题而简化的。

【问题讨论】:

  • 我认为您不应该在单元测试中使用 WPF Dispatcher:stackoverflow.com/a/9347908/1768303
  • 好点。由于生产代码的样子,我认为我需要使用它,但现在我看到我只在测试代码中使用了 Dispatcher。

标签: c# wpf unit-testing task-parallel-library


【解决方案1】:

在这里。

我的调试技能需要提高(除此之外)。问题不在于Dispatcher.BeginInvoke(),而是我如何处理结果。

QueueTask 的这个实现解决了这个问题:

protected override void QueueTask(Task task)
{
    var method = new Func<bool>(delegate
        {
            bool success = TryExecuteTask(task);
            if (task.IsFaulted)
            {
                throw new Exception("Invoke", task.Exception);
            }
            return success;
        });
    _dispatcher.BeginInvoke(method);
}

现在,收听Dispatcher.CurrentDispatcher.UnhandledException 工作正常:

Dispatcher.CurrentDispatcher.UnhandledException += OnDispatcherUnhandledException;

private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
    Assert.Fail("Exception: {0}", e.Exception);
}

也就是说,我同意@Noseratio 的评论,即更好的解决方案是不在单元测试代码中使用 WPF Dispatcher。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-02
    • 1970-01-01
    • 2017-08-13
    • 2018-06-29
    • 2016-01-14
    • 1970-01-01
    • 2010-09-14
    相关资源
    最近更新 更多