【发布时间】:2015-02-05 18:18:22
【问题描述】:
我知道这个网站和其他网站上有几个类似的问题,但由于某种原因,这样做的标准方法似乎不适用于我的情况。实现此要求的正常方法是在相关Task.Factory.StartNew overload 中使用TaskScheduler.FromCurrentSynchronizationContext() 作为TaskScheduler 输入参数:
// Set uiTaskScheduler whilst on the UI thread
TaskScheduler uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
...
Task.Factory.StartNew(() => SomeMethodToRunAsynchronously(),
CancellationToken.None, TaskCreationOptions.None, uiTaskScheduler);
看来这足以安排Task 在 UI 线程上运行,但在我的情况下似乎不起作用。就我而言,我有一个 UiThreadManager 类,其中有一个 RunAsynchronously 方法:
public Task RunAsynchronously(Action method)
{
return Task.Run(method);
}
这部分工作得很好。我面临的问题是,在运行单元测试时,此类被替换为 MockUiThreadManager 类(两者都实现了应用程序代码使用的 IUiThreadManager 接口),我似乎无法强制 this 在 UI 线程上运行的方法:
public Task RunAsynchronously(Action method)
{
return Task.Factory.StartNew(() => method(),
CancellationToken.None, TaskCreationOptions.None, UiTaskScheduler);
}
MockUiThreadManager 类有一个static UiTaskScheduler 属性,该属性在 UI 线程上设置(如下所示),因此我假设通过上述方法的所有代码都会在该线程上按预期运行:
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
MockUiThreadManager.UiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
但是,在运行单元测试时,我注意到它在它正在测试的代码之前完成了。因此,我添加了一些断点,并在每个断点的 Visual Studio 即时窗口中调用System.Threading.Thread.CurrentThread.ManagedThreadId,果然,当代码通过上述方法时,线程 ID 发生了变化。
所以基本上,我正在寻找一种方法来伪造基于Task 的异步调用在单元测试期间运行的RunAsynchronously 方法,以确保该方法实际同步运行在 UI 线程上。有没有人看到我做错了什么,或者有什么其他建议?
更新>>>
好的,我在这里使用了错误的关于 UI 线程的术语。单元测试不会在 UI 线程上运行,因为没有 UI……但是,情况保持不变。为了澄清,我只需要我的测试来同步运行应用程序代码,并在它启动的 main 单线程上运行。问题是应用程序运行时,有很多基于Task的异步代码,需要通过MockUiThreadManager类同步测试。
【问题讨论】:
-
这对我来说似乎很反直觉。通常,当您运行
Task.Factory.StartNew时,您将在 UI 线程上。 -
UiSynchronizationContext传递给StartNew的值是多少?向我们展示您在测试中如何调用Task.Factory.StartNew。 -
通常,当您运行 Task.Factory.StartNew 时,您将在 UI 线程上...这完全不正确,因为这完全取决于当前上下文。 @YuvalItzchakov,你的意思是
UiTaskScheduler?我没有将它传递给StartNew方法......正如我在问题中所说,我在 UI 线程上初始化它......在 Intellisense 中,它只是说Id=1,所以它绝对不是null。另外,我在测试中没有调用StartNew,而是调用了上面显示的(IMockUiThreadManager)RunAsynchronously方法。 -
@Sheridan 您是否考虑过简单地执行
Action并使用Task.FromResult将其包装在Task中? -
@Sheridan:共享
SynchronizationContext对象所涉及的技术不正是您要寻找的吗? IE。在IUiThreadManager的SynchronizationContext内调用测试?
标签: c# unit-testing asynchronous task