我知道在本网站和其他网站上有几个类似的问题,但标准的解决方法似乎在我的情况下不起作用。完成此要求的正常方法是在相关的Task.Factory.StartNew
重载中,将TaskScheduler.FromCurrentSynchronizationContext()
作为TaskScheduler
输入参数使用:
// Set uiTaskScheduler whilst on the UI thread
TaskScheduler uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
...
Task.Factory.StartNew(() => SomeMethodToRunAsynchronously(),
CancellationToken.None, TaskCreationOptions.None, uiTaskScheduler);
看起来这就足以在UI线程上安排一个Task
来运行,但在我的情况下似乎并不起作用。在我的情况下,我有一个UiThreadManager
类,它除了其他事情之外还有一个RunAsynchronously
方法:
public Task RunAsynchronously(Action method)
{
return Task.Run(method);
}
这部分工作很好。我面临的问题是,当运行单元测试时,这个类被一个MockUiThreadManager
类替换了(两者都实现了应用程序代码使用的IUiThreadManager
接口),而我似乎无法强制让此方法在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
的异步调用,使其在运行单元测试期间确保该方法实际上在 UI 线程上同步运行。有人看出我做错了什么,或者有其他建议吗?更新>>> 好的,关于 UI 线程,我在这里使用了错误的术语。单元测试不在 UI 线程上运行,因为没有 UI... 但是,情况仍然相同。为了澄清,我只需要我的测试在应用程序代码上同步地运行,并且在它开始的主单个线程上运行。问题在于当应用程序正在运行时,会有很多基于
Task
的异步代码,这需要通过 MockUiThreadManager
类进行同步测试。
Task.Factory.StartNew
时,你会在 UI 线程上。 - AronUiSynchronizationContext
传递给StartNew
时,它的值是多少?请展示一下您在测试中如何调用Task.Factory.StartNew
。 - Yuval ItzchakovUiTaskScheduler
吗?我没有将其传递给StartNew
方法...正如我在问题中所说,我在UI线程上初始化它...在Intellisense中,它只显示Id=1
,因此它绝对不是null
。此外,我没有在我的测试中调用StartNew
,我调用了(IMockUiThreadManager
)RunAsynchronously
方法,如上所示。 - SheridanMockUiThreadManager
的StartNew()
调用中传递TaskScheduler.FromCurrentSynchronizationContext()
而不是UiTaskScheduler
了吗? - toadflakz