我正在对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应用程序中也可以引发相同的异常?
答案 0 :(得分:1)
我的印象是,等待后的语句返回到“原始”上下文(已知
Application.Current.MainWindow
)。
只要您调用SynchronizationContext
时有任何要捕获的上下文,它就会在捕获的await
上继续。
在MSTest单元测试的上下文中,System.Threading.SynchronizationContext.Current
返回null
,因此Task
完成后就没有上下文可以恢复。
您可以尝试通过调用SynchronizationContext
来设置SynchronizationContext.SetSynchronizationContext
。 WPF应用程序默认使用System.Windows.Threading.DispatcherSynchronizationContext
。