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

.NET 7 WebApi集成测试中Hangfire构建失败问题求助

解决.NET 7 WebApi集成测试中Hangfire导致的构建失败问题

针对你遇到的System.InvalidOperationException报错(关联Hangfire.PostgreSql初始化失败),以下是几种可行的解决方案,根据你的测试需求选择即可:

方案1:替换Hangfire为内存存储并修正服务配置

如果需要保留Hangfire基础功能但不想依赖真实PostgreSQL数据库,可在测试工厂中完全替换Hangfire的存储及相关服务:

public class CustomWebApplicationFactory : WebApplicationFactory<Program>
{
    public Mock<IAnimals> animals { get; }

    public CustomWebApplicationFactory()
    {
        animals = new Mock<IAnimals>();
    }

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        base.ConfigureWebHost(builder);

        builder.ConfigureTestServices(services =>
        {
            // 替换EF内存数据库
            var dbContextOpt = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<AppDbContext>));
            if (dbContextOpt != null) services.Remove(dbContextOpt);
            services.AddDbContext<AppDbContext>(opt => 
                opt.UseInMemoryDatabase($"IntegrationTestDb_{DateTime.Now.ToFileTimeUtc()}"));

            // 清理Hangfire原有服务
            services.RemoveAll(typeof(IGlobalConfiguration));
            services.RemoveAll(typeof(HangfireServiceOptions));
            services.RemoveAll(typeof(IHostedService), s => s.ImplementationType?.Name.Contains("Hangfire") ?? false);

            // 添加内存存储的Hangfire配置
            services.AddHangfire(config => config
                .UseSimpleAssemblyNameTypeSerializer()
                .UseRecommendedSerializerSettings()
                .UseMemoryStorage());
            // 测试中不需要执行任务可注释掉下面一行
            // services.AddHangfireServer();

            // 注入Mock服务
            services.AddSingleton(animals.Object);
            services.AddLogging(b => b.AddConsole().AddDebug());
        });
    }
}

方案2:模拟Hangfire核心接口,完全跳过初始化

如果不需要Hangfire在测试中运行,直接模拟其关键接口,避免加载任何Hangfire服务:

public class CustomWebApplicationFactory : WebApplicationFactory<Program>
{
    public Mock<IAnimals> animals { get; }

    public CustomWebApplicationFactory()
    {
        animals = new Mock<IAnimals>();
    }

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        base.ConfigureWebHost(builder);

        builder.ConfigureTestServices(services =>
        {
            // 替换EF内存数据库
            var dbContextOpt = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<AppDbContext>));
            if (dbContextOpt != null) services.Remove(dbContextOpt);
            services.AddDbContext<AppDbContext>(opt => 
                opt.UseInMemoryDatabase($"IntegrationTestDb_{DateTime.Now.ToFileTimeUtc()}"));

            // 移除所有Hangfire相关服务
            services.RemoveAll(typeof(IBackgroundJobClient));
            services.RemoveAll(typeof(IRecurringJobManager));
            services.RemoveAll(typeof(IGlobalConfiguration));
            services.RemoveAll(typeof(IHostedService), s => s.ImplementationType?.Name.Contains("Hangfire") ?? false);

            // 注入Mock的Hangfire接口
            services.AddSingleton(new Mock<IBackgroundJobClient>().Object);
            services.AddSingleton(new Mock<IRecurringJobManager>().Object);

            // 注入Mock服务
            services.AddSingleton(animals.Object);
            services.AddLogging(b => b.AddConsole().AddDebug());
        });
    }
}

方案3:通过环境条件跳过Hangfire配置

在Program.cs中根据环境判断是否加载Hangfire,测试环境下直接跳过:

// Program.cs中的Hangfire配置部分
var isTestEnv = builder.Environment.IsEnvironment("Test");
if (!isTestEnv)
{
    var connectionString = builder.Configuration.GetConnectionString("PostgreSQLConnection");
    builder.Services.AddHangfire(config => config
        .UseSimpleAssemblyNameTypeSerializer()
        .UseRecommendedSerializerSettings()
        .UseStorage(new PostgreSqlStorage(connectionString)));
    builder.Services.AddHangfireServer();
}

然后在测试工厂中设置测试环境:

public class CustomWebApplicationFactory : WebApplicationFactory<Program>
{
    public Mock<IAnimals> animals { get; }

    public CustomWebApplicationFactory()
    {
        animals = new Mock<IAnimals>();
    }

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        base.ConfigureWebHost(builder);
        // 指定测试环境
        builder.UseEnvironment("Test");

        builder.ConfigureTestServices(services =>
        {
            // 替换EF内存数据库
            var dbContextOpt = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<AppDbContext>));
            if (dbContextOpt != null) services.Remove(dbContextOpt);
            services.AddDbContext<AppDbContext>(opt => 
                opt.UseInMemoryDatabase($"IntegrationTestDb_{DateTime.Now.ToFileTimeUtc()}"));

            // 注入Mock服务
            services.AddSingleton(animals.Object);
            services.AddLogging(b => b.AddConsole().AddDebug());
        });
    }
}

方案选择建议

  • 方案1:适合需要验证Hangfire调用逻辑,但不想依赖真实数据库的场景
  • 方案2:适合仅需测试业务逻辑,完全不需要Hangfire参与的场景
  • 方案3:适合彻底隔离测试环境与生产环境配置的场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 17:13:12