WinForms – why does mstest hang while waiting for windowsformssynchronizationcontext?

I have a custom windows forms control that contains mstest unit tests I added a @ r to this class_ 419_ 2271 @, I need to overwrite it, but new tests always timeout

After some experiments, I simplified the problem to control creation and waiting

[TestMethod]
public async Task TestMethod1()
{
    Control c = new Control();
    await Task.Delay(1);
}

I noticed that the test takes synchronizationcontext Current is set to null to start, and then once the control is created, it changes to windowsformssynchronizationcontext If I force the synchronization context to return null, the test will pass

[TestMethod]
public async Task TestMethod1()
{
    Control c = new Control();
    SynchronizationContext.SetSynchronizationContext(null);
    await Task.Delay(1);
}

Is there a way to use await from Windows Forms synchronization context without blocking?

Solution

Windows forms controls assume that they run in a Windows Forms application, but unit tests do not That's why your unit tests hang up

More specifically, the WinForms control installs a windowsformssynchronizationcontext that delegates work to application Win32 message loop in run So your @ r_ 419_ 2271 @ will view the context and continue to drain it into the message loop However, there is no actual message loop because your unit test will not call application Run.

The best solution IMO is to use MVVM mode. You do not test UI elements outside the UI application, so you will never encounter this situation (in MVVM, you need to unit test the logical UI instead of the literal UI) Using the MVVM method, your code will be as follows:

[TestMethod]
public async Task TestMethod1()
{
  viewmodel vm = new viewmodel();
  await vm.MethodAsync();
}

However, if you really need to unit test the actual UI elements, you can use the type similar to Windows Forms context contained in async CTP:

[TestMethod]
public async Task TestMethod1()
{
    await WindowsFormsContext.Run(async () =>
    {
        Control c = new Control();
        await Task.Delay(1);
    });
}
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>