I'm unit testing a part of my WPF project that uses async
code and Application.Current.MainWindow
to set the title of the main window.
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";
}
}
The unit test with the synchronous method succeeds while the async method throws the following exception when accessing Application.Current.MainWindow
after the await
:
System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.
[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";
}
}
I was under the impression that the statement after await
returns to the "original" context (where Application.Current.MainWindow
was known).
Why does the async
unit test throw an exception?
Is the reason unit test specific or can the same exception be thrown in my WPF application too?