.NET Core 在集成测试中停止 HostedService

CF7*_*CF7 9 c# integration-testing asp.net-core-hosted-services

我有 .NET Core Web API 项目,由于某些原因,我们在该项目中创建了一个后台服务,并在应用程序启动时开始运行后台服务。因此,我们创建了一个BackgroundWorkderService继承自BackgroundService (Microsoft.Extensions.Hosting)的 ,如下所示:

public class BackgroundWorkerService : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        await DoWork(stoppingToken);
    }

    public override async Task StartAsync(CancellationToken cancellationToken)
    {
        await ExecuteAsync(cancellationToken);
    }

    public override Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }
}
Run Code Online (Sandbox Code Playgroud)

为了在应用程序启动时运行它,我将后台服务添加到 Program.cs 中的托管服务中,如下所示:

.ConfigureServices(services =>
                services.AddHostedService<BackgroundWorkerService>());
Run Code Online (Sandbox Code Playgroud)

现在,我们需要创建一个集成测试,并且我们希望在运行集成测试时停止后台服务。

有谁知道如何在集成测试中阻止它?我尝试从ConfigureTestServices 中删除该服务,但没有成功,集成测试开始时后台服务仍在运行。

Cam*_*ein 12

正如您在问题中提到的,您应该能够删除 中的服务ConfigureTestServices。然而,我们如何指定要删除的服务是这里的关键。

根据我的经验,您需要找到有问题的值ServiceDescriptor,而不是创建一个具有预期值的新值(请参阅下面的注释了解原因)。我使用 LINQ 和服务的实现BackgroundWorkerService类型(在您的情况下为)来轻松查找现有的ServiceDescriptor. 然后我可以将其从列表中删除,这意味着CreateClient()WebApplicationFactory.

看起来像这样:

builder.ConfigureTestServices(services =>
{
    var descriptor = services.Single(s => s.ImplementationType == typeof(BackgroundWorkerService));
    services.Remove(descriptor);
}
Run Code Online (Sandbox Code Playgroud)

这种方法的一个非常好的好处是,它将测试逻辑保留在生产代码之外,并完全保留在测试的设置/夹具中。

关于IServiceCollection删除的注意事项:经过一番研究,我相信这是因为ServiceDescriptor除了 之外没有提供相等或比较方法Object.Equals,该方法回退到引用相等。因此,即使 new 中的所有值都相同ServiceDescriptor,它们也会是不同的对象,因此不会被发现并从服务列表中删除。


CF7*_*CF7 1

我找到了一个解决方案,将后台服务寄存器置于如下状态。

在注册后台服务部分编辑 Program.cs 文件,如下所示:

.ConfigureServices(services =>
        {
            if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") != "INTEGRATION")
            {
                services.AddHostedService<BackgroundWorkerService>();
            }
        });
Run Code Online (Sandbox Code Playgroud)

然后尝试将变量从您需要的位置更改为 INTEGRATION。