VsixTesting icon indicating copy to clipboard operation
VsixTesting copied to clipboard

Fix: non-async tests hang sometimes when UIThread = true

Open josetr opened this issue 6 years ago • 6 comments
trafficstars

Xunit.Sdk.AsyncTestSyncContext seems to be the problem and it's only purpose is to support async void test methods.

So the problem is solved if we dodge it when the test method is not async and UIThread = true.

josetr avatar Jun 02 '19 19:06 josetr

It might be worth considering an alternative where the test is immediately reported as failing if it's a UI thread test but isn't async Task. It's limiting in theory, but it probably isn't what you want anyway.

sharwell avatar Jun 02 '19 23:06 sharwell

Apparently async void tests suffer from the same problem. The call to WaitForCompletionAsync never completes on both cases. async Task tests do work because they do not call WaitForCompletionAsync at all.

Task taskFromResult = GetTaskFromResult(CallTestMethod(testClassInstance));
if (taskFromResult != null)
    await taskFromResult;
else
{
    Exception ex = await asyncSyncContext.WaitForCompletionAsync();
  
}

josetr avatar Jun 03 '19 16:06 josetr

It's interesting that xunit has a way to run async void tests in most cases, but it's not especially valuable. async void should never be used in unit tests or otherwise. Visual Studio extension code will typically be running the vs-threading analyzers which reports a warning for violations of this, so I would not expect async void tests to appear in code using this library.

sharwell avatar Jun 03 '19 16:06 sharwell

Agree I just wanted to point out that it didn't work since my pull request didn't account for it.

I'm still not sure whether we shouldn't allow synchronous UI tests to just work.

It's much simpler to play with this library if it does, and I'm guessing there are still methods that just call ThreadHelper.ThrowIfNotOnMainThread() at the beginning in the wild.

Should those be avoided if possible by the way?

I'm just making them async and then calling SwitchToMainThreadAsync but just wondering what's the best practice here.

josetr avatar Jun 04 '19 14:06 josetr

💭 If you want to undo the AsyncTestSyncContext, you can override CallTestMethod and add this before calling the base implementation:

SynchronizationContext.SetSynchronizationContext(GetEffectiveSynchronizationContext());

Where GetEffectiveSynchronizationContext comes from here:

https://github.com/dotnet/roslyn/blob/948a9e1da970618d8e04cfd254b62659139ae9af/src/Workspaces/CoreTestUtilities/TestExportJoinableTaskContext.cs#L73-L91

sharwell avatar Jun 04 '19 16:06 sharwell

Not sure if that helps or not.

sharwell avatar Jun 04 '19 16:06 sharwell