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

.NET 8中如何对AspNetCore应用启动进行单元测试?

.NET 8 中复用应用启动配置进行DI验证单元测试

之前在.NET 6里,我通过WebHost Builder结合Startup类做API的单元测试,验证配置和依赖注入(DI)的正确性。升级到.NET 8后,采用了program.cs的简洁写法,原来的单元测试失效了。我想只在一处维护应用启动逻辑,让单元测试直接复用这套配置。

旧.NET 6启动方式

public static IHostBuilder CreateHostForDependencyInjectionTests(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            var env = hostingContext.HostingEnvironment;

            config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

            if (args != null)
            {
                config.AddCommandLine(args);
            }
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        })
        // Add a new service provider configuration
        .UseDefaultServiceProvider((context, options) =>
        {
            options.ValidateScopes = true;
            options.ValidateOnBuild = true;
        });

原单元测试代码

[TestCase("Development")]
[TestCase("Production")]
public void DependencyRegistrationIsValid(string env)
{
    Environment.SetEnvironmentVariable("DOTNET_ENVIRONMENT", env);

    var hostBuilder = WebApiHostBuilder.CreateHostForDependencyInjectionTests(new string[0]);

    var host = hostBuilder.Build();

    Assert.NotNull(host);
}

升级后的问题

升级到.NET 8后不能再用Startup类,尝试往builder.WebHost里加相关配置会触发ASP0010错误。

我的新.NET 8 program.cs代码:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.ConfigureSwagger();

var app = builder.Build();

// Configure the HTTP request pipeline.

app.UseSwagger();
app.UseSwaggerUI();

app.UseCustomExceptionHandler();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

我希望能在单元测试里启动API应用,让所有配置或DI的错误直接抛出来,方便修复。


解决方案

要实现一处维护启动逻辑、单元测试复用的目标,可以把program.cs里的配置逻辑抽成可复用的方法,同时避免ASP0010错误。

步骤1:重构program.cs,抽离配置逻辑

把服务注册和中间件配置拆成单独的扩展方法,让单元测试可以直接调用:

var builder = WebApplication.CreateBuilder(args);

// 复用抽离的服务注册逻辑
builder.ConfigureServices();

var app = builder.Build();

// 复用抽离的中间件配置逻辑
app.ConfigurePipeline();

app.Run();

// 扩展方法可放在同一命名空间或单独类库中
public static class ApplicationConfiguration
{
    public static WebApplicationBuilder ConfigureServices(this WebApplicationBuilder builder)
    {
        builder.Services.AddControllers();
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen();
        builder.Services.ConfigureSwagger();
        
        // 保留DI验证配置
        builder.Host.UseDefaultServiceProvider((context, options) =>
        {
            options.ValidateScopes = true;
            options.ValidateOnBuild = true;
        });
        
        // 复用原配置加载逻辑
        builder.Configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
        if (builder.Args != null)
        {
            builder.Configuration.AddCommandLine(builder.Args);
        }
        
        return builder;
    }
    
    public static WebApplication ConfigurePipeline(this WebApplication app)
    {
        // 环境判断保留原逻辑
        if (app.Environment.IsDevelopment())
        {
            app.UseSwagger();
            app.UseSwaggerUI();
        }

        app.UseCustomExceptionHandler();
        app.UseHttpsRedirection();
        app.UseAuthorization();
        app.MapControllers();
        
        return app;
    }
}

步骤2:创建可复用的测试用应用构建方法

适配.NET 8的WebApplication模型,构建应用但不启动HTTP服务器:

public static class WebApiHostBuilder
{
    public static WebApplication CreateApplicationForTests(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);
        
        // 复用program.cs中的服务配置
        builder.ConfigureServices();
        
        // 构建应用但不启动
        var app = builder.Build();
        
        // 复用中间件配置
        app.ConfigurePipeline();
        
        return app;
    }
}

步骤3:修改单元测试代码

直接调用新的构建方法,验证DI和配置的正确性:

[TestCase("Development")]
[TestCase("Production")]
public void DependencyRegistrationIsValid(string env)
{
    Environment.SetEnvironmentVariable("DOTNET_ENVIRONMENT", env);

    var app = WebApiHostBuilder.CreateApplicationForTests(new string[0]);

    Assert.NotNull(app);
    
    // 可选:验证特定服务是否正确注册
    var serviceProvider = app.Services;
    var controllerActivator = serviceProvider.GetService<IControllerActivator>();
    Assert.NotNull(controllerActivator);
}

关键说明

  • 抽离扩展方法后,program.cs和单元测试共用同一套配置逻辑,无需重复维护。
  • 构建应用时不调用Run(),避免启动HTTP服务器,专注于DI和配置验证。
  • 保留UseDefaultServiceProvider的验证配置,确保DI注册错误在构建阶段就抛出,提前发现问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 20:28:11