Windows Forms controls assume that they are running inside a Windows Forms application, which is not the case for unit tests. That is why your unit test is hanging.
To be more specific, WinForms controls install a WindowsFormsSynchronizationContext
that delegates work to the Win32 message loop inside Application.Run
. So, your async
method sees the context and queues its continuation to that message loop. However, there is no actual message loop because your unit test doesn't ever call Application.Run
.
The best solution IMO is to use an MVVM pattern where you do not test UI elements outside of a UI application, so you never run into this situation (in MVVM, you unit test the logical UI but not the literal UI). With an MVVM approach your code would look like this:
[TestMethod]
public async Task TestMethod1()
{
ViewModel vm = new ViewModel();
await vm.MethodAsync();
}
But if you do want to unit test the actual UI elements, you can use a type like the Windows Forms Context that was included in the Async CTP:
[TestMethod]
public async Task TestMethod1()
{
await WindowsFormsContext.Run(async () =>
{
Control c = new Control();
await Task.Delay(1);
});
}