TaskScheduler.FromCurrentSynchronizationContext - 如何在单元测试时使用WPF调度程序线程

时间:2011-11-10 10:35:06

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

我在ViewModel中有代码通过任务调用服务。 任务完成后,它将填充ObservableCollection。 问题是它正在等待任务完成,使用ContinueWith方法并提供TaskScheduler.FromCurrentSynchronizationContext作为任务调度程序,以便在UI线程上更新OC。

到目前为止一直很好,但是当谈到单元测试时,它会抛出一个异常,说“当前的SynchronizationContext可能不会被用作TaskScheduler”。 如果我在单元测试中使用模拟SynchronizationContext,那么ObservableCollection会抛出一个错误,因为它是根据调度程序线程进行更新的。

有什么方法可以解决这个问题吗?

感谢。

3 个答案:

答案 0 :(得分:17)

这并不容易,但也不是那么难。你需要做的是启动一个作为STA设置的工作线程,然后在其上启动Dispatcher运行时。一旦你让那个工人坐在那里,你可以从单元测试线程向它发送工作,显然,这些线程没有为这种工作进行初始化。首先,这是您在测试设置中启动调度程序线程的方法:

this.dispatcherThread = new Thread(() =>
{
   // This is here just to force the dispatcher infrastructure to be setup on this thread
   Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>
   {
       Trace.WriteLine("Dispatcher worker thread started.");
   }));

   // Run the dispatcher so it starts processing the message loop
   Dispatcher.Run();
});

this.dispatcherThread.SetApartmentState(ApartmentState.STA);
this.dispatcherThread.IsBackground = true;
this.dispatcherThread.Start();

现在,如果您想在测试清理中干净地关闭该线程,我建议您这样做,您只需执行以下操作:

Dispatcher.FromThread(this.dispatcherThread).InvokeShutdown();

所以,所有这些基础设施的东西都在这里,在测试中你需要做的就是在那个线程上执行。

public void MyTestMethod
{
    // Kick the test off on the dispatcher worker thread synchronously which will block until the work is competed
    Dispatcher.FromThread(this.dispatcherThread).Invoke(new Action(() =>
    {
        // FromCurrentSynchronizationContext will now resolve to the dispatcher thread here
    }));
}

答案 1 :(得分:14)

将此添加到测试初始化​​中,以创建上下文:

SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());

答案 2 :(得分:0)

这使它更简单

TaskScheduler scheduler = Dispatcher.CurrentDispatcher.Invoke(TaskScheduler.FromCurrentSynchronizationContext)

然后您的代码可以显式使用scheduler(在运行时使用TaskScheduler.FromCurrentSynchronizationContext()初始化)