c# - 为什么我的异步单元测试会抛出 InvalidOperationException 而同一个同步测试不会?
问题描述
我正在对我的 WPF 项目的一部分进行单元测试,该项目使用async
代码并Application.Current.MainWindow
设置主窗口的标题。
public class ClassUnderTest
{
// Get and apply title async
public async Task GetAndApplyWindowTitleFromDbAsync()
{
string windowTitle = await GetWindowTitleFromDbAsync();
Application.Current.MainWindow.Title = windowTitle;
}
public async Task<string> GetWindowTitleFromDbAsync()
{
await Task.Delay(2000);
return "Async Window Title";
}
// Get and apply title sync
public void GetAndApplyWindowTitleFromDb()
{
Application.Current.MainWindow.Title = "Sync Window Title";
}
}
同步方法的单元测试成功,而异步方法在之后访问时抛出以下Application.Current.MainWindow
异常await
:
System.InvalidOperationException:调用线程无法访问此对象,因为不同的线程拥有它。
[TestClass]
public class TestClass
{
[TestMethod]
public void SyncMethodWithUICodeTest()
{
InitializeApplication();
Assert.AreEqual("Window Title", Application.Current.MainWindow.Title);
var classUnderTest = new ClassUnderTest();
classUnderTest.GetAndApplyWindowTitleFromDb();
// Test succeeds
Assert.AreEqual("Sync Window Title", Application.Current.MainWindow.Title);
}
[TestMethod]
public async Task AsyncMethodWithUICodeTest()
{
InitializeApplication();
Assert.AreEqual("Window Title", Application.Current.MainWindow.Title);
var classUnderTest = new ClassUnderTest();
await classUnderTest.GetAndApplyWindowTitleFromDbAsync();
// throws InvalidOperationException
Assert.AreEqual("Async Window Title", Application.Current.MainWindow.Title);
}
private void InitializeApplication()
{
if (Application.Current == null)
{
var app = new Application();
var window = new Window();
app.MainWindow = window;
}
Application.Current.MainWindow.Title = "Window Title";
}
}
我的印象是,之后的声明await
返回到“原始”上下文(Application.Current.MainWindow
已知的地方)。
为什么async
单元测试会抛出异常?单元测试的原因是特定的还是可以在我的 WPF 应用程序中引发相同的异常?
解决方案
我的印象是 await 之后的语句返回到“原始”上下文(
Application.Current.MainWindow
已知的位置)。
SynchronizationContext
如果在您调用时有任何要捕获的上下文,它会在捕获时恢复await
。
在 MSTest 单元测试的上下文中,System.Threading.SynchronizationContext.Current
返回null
,因此一旦完成就没有上下文可以恢复Task
。
您可以尝试SynchronizationContext
通过调用来设置SynchronizationContext.SetSynchronizationContext
. WPF 应用程序System.Windows.Threading.DispatcherSynchronizationContext
默认使用 a。
推荐阅读
- reactjs - React 没有推送数组中的项目
- mysql - 如何修复mysql中的“正确的语法以在'附近使用'作为开始”错误?
- python - TypeError:“模块”对象不可调用 - 无法显示我的训练数据集散点图
- html - Keydown 在 onChange on 之前触发
- swift - 使用闭包将变量信息传递给第一个 VC 时遇到问题
- spring-cloud-gateway - Spring Cloud Gateway Redis 限速器不起作用
- java - 没有冲突时如何使用spring jpa将记录插入数据库
- reactjs - 添加换行符 javascript
- unreal-engine4 - 虚幻引擎蓝图:如何沿样条线移动演员?
- oracle - oracle客户端无法显示泰文