You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在集成/端到端测试中启动完整.NET Core Worker Service?

如何为.NET Core Worker Service实现类似WebApplicationFactory的集成测试方案

在.NET Core Web应用的集成测试中,我们可以使用WebApplicationFactory便捷托管被测应用并开展测试,但Worker Service没有现成的同类工厂类可用。我需要找到一种直接通过.NET Core启动Worker Service的方式编写端到端测试——目前已通过Docker容器+Testcontainers实现类似测试,但Docker方式调试被测单元十分不便。

现有的Worker Service代码如下:

Program.cs

// Program.cs

using SampleWorker;

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services => { services.AddHostedService<Worker>(); })
    .Build();

host.Run();

Worker.cs

// Worker.cs

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;

    public Worker(ILogger<Worker> logger)
    {
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // - 连接中间件(数据源)
        // - 连接数据库(数据接收器)
        // - 从中间件接收事件,转换后持久化到数据库
    }
}

我期望编写的测试代码框架如下,核心问题是如何替代注释中不存在的WorkerFactory<Program>,直接启动带有Program.cs中所有配置的SampleWorker:

public class E2eTest
{
    /// <summary>
    /// 测试事件的完整处理流程:
    /// - 被Worker Service捕获
    /// - 处理与转换
    /// - 持久化到数据库
    /// </summary>
    [Fact]
    public void EventIsProcessedAndWrittenToDatabase()
    {
        // 准备
        // - 启动作为数据源的中间件(Testcontainers)
        // - 启动作为数据接收器的数据库(Testcontainers)
        
        // TODO 没有现成的WorkerFactory,如何启动带有Program.cs所有配置的SampleWorker?
        var unitUnderTest = new WorkerFactory<Program>();
        
        // 执行
        // - 向中间件(数据源)发布事件
        
        // 断言
        // - 检查数据库(数据接收器)中是否有对应的记录
    }
}

解决方案:自定义Host托管逻辑替代WorkerFactory

1. 调整Program.cs使其支持测试场景引用

修改Program.cs,将Host的创建逻辑暴露为可访问方法,方便测试项目调用:

// Program.cs

using SampleWorker;

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    // 暴露给测试项目的Host构建方法
    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices(services => { services.AddHostedService<Worker>(); });
}

2. 在测试中直接构建并控制Host

在测试类中,直接调用Program.CreateHostBuilder构建Host,手动控制启动和停止,实现类似WebApplicationFactory的效果:

public class E2eTest : IAsyncLifetime
{
    private IHost _host;
    // 可在此定义Testcontainers实例,比如中间件容器和数据库容器
    // private readonly IContainer _middlewareContainer;
    // private readonly IContainer _dbContainer;

    public async Task InitializeAsync()
    {
        // 1. 启动Testcontainers的数据源和数据接收器
        // await _middlewareContainer.StartAsync();
        // await _dbContainer.StartAsync();

        // 2. 构建并启动Worker Service的Host
        var hostBuilder = Program.CreateHostBuilder(Array.Empty<string>())
            // 可选:覆盖测试所需配置,比如数据库连接字符串、中间件地址等
            .ConfigureAppConfiguration((context, config) =>
            {
                config.AddInMemoryCollection(new Dictionary<string, string>
                {
                    // 从Testcontainers获取实际地址,替换配置项
                    // ["Middleware:Url"] = _middlewareContainer.GetConnectionString(),
                    // ["Database:ConnectionString"] = _dbContainer.GetConnectionString()
                });
            });

        _host = hostBuilder.Build();
        // 启动Host但不阻塞主线程(与WebApplicationFactory逻辑一致)
        await _host.StartAsync();
    }

    [Fact]
    public async Task EventIsProcessedAndWrittenToDatabase()
    {
        // 执行:向中间件发布事件
        // var middlewareClient = new MiddlewareClient(_middlewareContainer.GetConnectionString());
        // await middlewareClient.PublishEventAsync(new TestEvent());

        // 等待Worker处理事件(根据实际逻辑调整等待时长,或使用更可靠的等待方式)
        await Task.Delay(2000);

        // 断言:检查数据库中是否有记录
        // var dbContext = _host.Services.GetRequiredService<AppDbContext>();
        // var processedEvent = await dbContext.ProcessedEvents.FirstOrDefaultAsync();
        // Assert.NotNull(processedEvent);
        // Assert.Equal("TestEvent", processedEvent.Type);
    }

    public async Task DisposeAsync()
    {
        // 停止Host
        if (_host != null)
        {
            await _host.StopAsync();
            _host.Dispose();
        }

        // 停止Testcontainers容器
        // await _middlewareContainer.StopAsync();
        // await _dbContainer.StopAsync();
    }
}

关键说明

  • 利用IAsyncLifetime接口统一管理测试前后的资源启动/销毁,包括Host和Testcontainers容器
  • 通过ConfigureAppConfiguration可轻松覆盖测试环境配置,确保Worker连接到Testcontainers提供的数据源和数据库
  • 该方式直接在测试进程内启动Worker Service,完全支持本地调试,可设置断点追踪Worker执行逻辑

内容的提问来源于stack exchange,提问作者samba2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 18:54:58