C# 如何在具有Task.Yield的后台服务上编写测试?

C# 如何在具有Task.Yield的后台服务上编写测试?,c#,asp.net-core,async-await,xunit,C#,Asp.net Core,Async Await,Xunit,我有以下后台服务: public class MyBackgroundService : BackgroundService { protected override async Task ExecuteAsync(CancellationToken stoppingToken) { // Required for the method to be executed asynchronously, allowing star

我有以下后台服务:

    public class MyBackgroundService : BackgroundService
    {
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            // Required for the method to be executed asynchronously, allowing startup to continue.
            await Task.Yield();
            while (!stoppingToken.IsCancellationRequested)
            {
                DoSomeWork();
            }
    }
然而,我正在努力测试这一点;我不能等待
ExecuteAsync
的完成,因为
Task.Yield()
只返回到当前上下文。所以在我的测试中,
等待服务。ExecuteAsync(令牌)
立即返回

如何在不使用
线程的情况下对其进行测试。在测试中使用
睡眠?

根据:

您可以使用wait Task.Yield();在异步方法中,强制该方法异步完成。如果存在当前同步上下文(SynchronizationContext对象),这将把方法执行的其余部分发回该上下文。但是,上下文将决定如何将此工作相对于其他可能待定的工作进行优先级排序。在大多数UI环境中,UI线程上存在的同步上下文通常会将发布到上下文的工作优先于输入和呈现工作。因此,不要依赖于wait Task.Yield();保持用户界面的响应性。有关更多信息,请参阅.NET并行编程博客中的条目“使用ContinueWith启用有用的抽象”

ASP.NET(默认情况下)没有同步上下文,但
Task.Yield
可能仍然有用:

static async Task Main()
{
    var t1 = DoSomethingLengthyWithYieldAsync();
    Console.WriteLine("Before await t1");
    await t1;
    Console.WriteLine("After await t1");
    
    Console.WriteLine("----------");

    var t2 = DoSomethingLengthyWithoutYieldAsync();
    Console.WriteLine("Before await t2");
    await t2;
    Console.WriteLine("After await t2");
}

async Task DoSomethingLengthyWithYieldAsync()
{
    Console.WriteLine("Before Task.Yield");
    await Task.Yield();
    Console.WriteLine("Before Thread.Sleep");
    Thread.Sleep(1);
    Console.WriteLine("After Thread.Sleep");
}

async Task DoSomethingLengthyWithoutYieldAsync()
{
    Console.WriteLine("Before Thread.Sleep");
    Thread.Sleep(1);
    Console.WriteLine("After Thread.Sleep");
}
使用
Task.Yield
,只要达到
wait Task.Yield()
,您就可以从异步方法调用中获得
Task

要提供有关特定用例的更多建议,我们需要查看
DoSomeWork()
的实现

我不能等待ExecuteAsync的完成,因为Task.Yield()只返回到当前上下文

我想您的意思是,您不能等待
StartAsync
返回的任务,因为
ExecuteAsync
保护


如果您想像这样对服务进行单元测试,我建议将您的逻辑拆分为单独的可测试类型
BackgroundService
“隐藏”作为私有成员的
ExecuteAsync
任务。

一些测试框架也支持异步测试,这意味着您可以在测试代码中等待要测试的异步方法。因为您使用的是xUnit,所以请确保您没有使用真正旧版本的xUnit,并且您应该很好。然后基本上你也需要让你的测试方法
async任务
,然后等待调用ExecuteAsync,其余的部分由xUnit负责。虽然
ExecuteAsync
会立即返回,但如果你真的在等待它返回的任务,等待操作不应立即返回-除非
stoppingToken
被取消。请提供一个非常有争议的设计。如果您想在线程池线程上运行一些代码,为什么不直接使用
Task.run
?或者在这种情况下,最好创建单独的线程(或者使用
longlunning
标志启动任务),因为您似乎正在执行一些长操作,而线程池并不是为其设计的。