【问题标题】:Integration Test for Hosted Service in .NET Core.NET Core 中托管服务的集成测试
【发布时间】:2021-07-30 10:47:01
【问题描述】:

我想测试一个 QueueTask 托管服务(.NET Core 的新后台服务)。我的 queuedHosted 服务如下所示:

public QueuedHostedService(IServiceProvider serviceProvider, IBackgroundTaskQueue taskQueue, ILoggerFactory loggerFactory)
{
    TaskQueue = taskQueue;
    _logger = loggerFactory.CreateLogger<QueuedHostedService>();
    _serviceProvider = serviceProvider;
}

protected async override Task ExecuteAsync(CancellationToken stoppingToken)
{
    using (var scope = _serviceProvider.CreateScope())
    {
        while (false == stoppingToken.IsCancellationRequested)
        {
            var workItem = await TaskQueue.DequeueAsync(stoppingToken);
            try
            {
                await workItem(scope.ServiceProvider, stoppingToken);
            }
            catch (Exception ex)
            {
                this._logger.LogError(ex, $"Error occurred executing {nameof(workItem)}.");
            }
        }
    }
}

它只是从队列中读取任务并在它们进入时执行它们。我已经验证了托管服务正在生产中工作。我像这样为它写了一个测试:

[TestMethod]
public async Task Verify_Hosted_Service_Executes_Task()
{
    IServiceCollection services = new ServiceCollection();
    services.AddSingleton<ILoggerFactory, NullLoggerFactory>();
    services.AddHostedService<QueuedHostedService>();
    services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();
    var serviceProvider = services.BuildServiceProvider();

    var backgroundQueue = serviceProvider.GetService<IBackgroundTaskQueue>();

    var isExecuted = false;
    backgroundQueue.QueueBackgroundWorkItem(async (sp, ct) => {
        isExecuted = true;
    });

    await Task.Delay(10000);
    Assert.IsTrue(isExecuted);
}

但是,我的回调从未被击中。如何让我的任务在后台服务上执行?

编辑

我在模仿启动,并假设我的后台服务可以正常工作, 但显然我的服务从未启动。

托管服务通常如何从 .NET Core 启动?

【问题讨论】:

  • 关于“如何启动您的托管服务?”您应该使用GenericHost 来运行您的IHostedService。您还需要配置服务依赖项。

标签: c# asp.net-core .net-core mstest asp.net-core-hosted-services


【解决方案1】:

托管服务由框架作为 WebHost 启动过程的一部分启动

// Fire IHostedService.Start
await _hostedServiceExecutor.StartAsync(cancellationToken).ConfigureAwait(false);

Source

通过HostedServiceExecutor,它将收集所有已注册的IHostedService,枚举它们并依次启动它们

public HostedServiceExecutor(ILogger<HostedServiceExecutor> logger, IEnumerable<IHostedService> services)
{
    _logger = logger;
    _services = services;
}

public async Task StartAsync(CancellationToken token)
{
    try
    {
        await ExecuteAsync(service => service.StartAsync(token));
    }
    catch (Exception ex)
    {
        _logger.ApplicationError(LoggerEventIds.HostedServiceStartException, "An error occurred starting the application", ex);
    }
}

Source

但由于您自己测试托管服务,因此您必须充当框架并自己启动服务。

[TestMethod]
public async Task Verify_Hosted_Service_Executes_Task() {
    IServiceCollection services = new ServiceCollection();
    services.AddSingleton<ILoggerFactory, NullLoggerFactory>();
    services.AddHostedService<QueuedHostedService>();
    services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();
    var serviceProvider = services.BuildServiceProvider();

    var service = serviceProvider.GetService<IHostedService>() as QueuedHostedService;

    var backgroundQueue = serviceProvider.GetService<IBackgroundTaskQueue>();

    await service.StartAsync(CancellationToken.None);

    var isExecuted = false;
    backgroundQueue.QueueBackgroundWorkItem(async (sp, ct) => {
        isExecuted = true;
    });

    await Task.Delay(10000);
    Assert.IsTrue(isExecuted);

    await service.StopAsync(CancellationToken.None);
}

【讨论】:

  • 我不得不使用 var service = serviceProvider.GetService();而不是 QueuedHostedService 来获取服务。
  • @user1568891 QueuedHostedService 直接指的是他们在问题中使用的类型。
  • @Nkosi 当我刚刚使用我也在 AddHostedService 中输入的类的类型时,GetService 为我返回了 null。在我将其更改为 IHostedService 之前,它不会返回我在 AddHostedService 中输入的类型。不过,也许我在做其他不同的事情。
  • @user1568891 那么问题出在我的代码上。经过进一步审查,您描述的行为是正确的,因为我没有看到该类与服务集合的直接注册。
  • 您还可以通过 serviceProvider.GetServices().OfType().Single(); 获得新服务(特别是如果您注册了多个 IHostedInstace);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-18
  • 2020-07-08
  • 1970-01-01
  • 2022-01-02
  • 2015-03-31
  • 2021-07-05
相关资源
最近更新 更多