异步不会在单元测试中的同一线程上继续

Async does not continue on same thread in unit test

给定以下代码:

public static async void CurrentThreadCall()
{
    Console.WriteLine("Begin on thread {0}", Thread.CurrentThread.ManagedThreadId);
    await BackgroundCall();
    Console.WriteLine("Completed on thread {0}", Thread.CurrentThread.ManagedThreadId);
}

private static async Task BackgroundCall()
{
    await Task
        .Run(() =>
            {
                Console.WriteLine("Task run on thread: {0}", Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(TimeSpan.FromMilliseconds(100));
            })
        .ConfigureAwait(false);
}

从 WPF 应用程序调用 CurrentThreadCall() 方法,Begin 和 Completed 输出将 运行 在相同的线程上(正如我所期望的):

BackgroundCall begin: 9
Task run on thread: 6
Completed on thread 9   <--- As expected

如果我从单元测试调用该方法并使用 ReSharper 测试运行ner(VS2015 中的 2016.2),Completed 输出将改为 运行 在与任务相同的线程上:

Begin on thread 11
Task run on thread: 4
Completed on thread 4   <-- Not what I expected

为什么会这样,我可以在我的测试中做一些事情让它像在 WPF 应用程序中一样工作吗?

我试过的...

我试过使测试方法异步:

[Test]
public async Task MyTest()
{
    await CurrentThreadCall();
}

无奈之下,我曾尝试set the SynchronizationContext自考:

[Test]
public void MyTest()
{
    SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
    CurrentThreadCall();
}

...运气不好。

await 运行 之后的任务继续在同一个同步上下文中,而不是在同一个线程中。对于 WPF 应用程序,同步上下文与调度程序相关联,并且只有一个调度程序线程。因此,同一线程上的延续 运行。在单元测试中,没有同步上下文,或者在您的示例中,它是与线程池关联的默认同步上下文。因此,可以在线程池中的任何线程上继续 运行。

如果您想在测试中完全重现该行为,您应该使用单线程同步上下文之一 - DispatcherSynchronizationContext 或例如https://github.com/StephenCleary/AsyncEx/wiki/AsyncContext