我可以使用ASP.NET Core 6+ WebApplicationBuilder?

wkftcu5l  于 2023-05-01  发布在  .NET
关注(0)|答案(1)|浏览(149)

Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory将引导ASP。NET Core应用程序在内存中进行单元测试。它通常通过发现和调用public static IHostBuilder CreateHostBuilder来实现这一点。
这个CreateHostBuilder方法是ASP的旧模式的一部分。NET Core 3.x/5,它使用了HostBuilder。现在我们得到了WebApplicationBuilder。测试WebApplicationFactory将调用Program.Main
我的问题是Program.Main做了一些我不想在单元测试中做的事情。
在单元测试中我不想要的东西:它从appsettings.jsonappsettings.ASPNETCORE_ENVIRONMENT.json设置了Serilog,我不希望在我的单元测试中这样做,这没有意义。这不是我可以控制WebApplicationFactory的东西,因为我在使用WebApplication.CreateBuilder之前就做了(我认为这是一个明智的决定:输入Main后,我的第一个优先事项是配置日志记录。以防万一)。
有没有办法说服WebApplicationFactory选择另一个入口点,允许我从单元测试中排除最基本的基础设施代码?
我必须回到旧的程序/启动模式吗?我是否做了一些错误的事情,应该重新考虑是否需要从测试中排除代码?
如果有关系,这里是我的Program类。尝试中的所有内容之前都是通过CreateHostBuilder(args).Build().Run()完成的,并且在Startup中:

public class Program
{
    public static int Main(string[] args)
    {
        ConfigureLogging(configuration);

        try
        {
            var builder = WebApplication.CreateBuilder(args);
            _ = builder.Host.UseSerilog();
            _ = builder.Services.AddControllers().AddJsonOptions ...
            ...

            var app = builder.Build();
            ...

            Dependencies.Register(container, app.Configuration);
            container.Verify();
            
            app.Run();  
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "Host terminated unexpectedly");
            return 1;
        }
        finally
        {
            Log.CloseAndFlush();
        }

        return 0;
    }

    private static void ConfigureLogging(IConfigurationRoot configuration)
    {
        var configuration = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
            .AddEnvironmentVariables()
            .Build();
        Log.Logger = new LoggerConfiguration()
                .ReadFrom.Configuration(configuration)
                .Enrich.FromLogContext()
                ...
    }
}

下面是我的测试WebApplicationFactory

internal class MyWebApplicationFactory : WebApplicationFactory<Program>
{
    private readonly Dictionary<string, string?> _appConfig;
    public IConfiguration? Configuration { get; private set; }

    public MyWebApplicationFactory(SqlSettings sqlSettings)
    {
        _appConfig = new Dictionary<string, string?>
        {
            { "SqlSettings:ConnectionString", sqlSettings.ConnectionString },
        };
    }

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        _ = builder.ConfigureAppConfiguration(config =>
        {
            // Clear config and replace with in memory
            // Won't affect anything that doesn't get config from app, like logging

            config.Sources.Clear();

            Configuration = new ConfigurationBuilder()
                .AddInMemoryCollection(_appConfig)
                .Build();
            _ = config.AddConfiguration(Configuration);
        });

        _ = builder.UseEnvironment("Test");
    }
}

如你所见我有机会转储配置并添加自己的配置以进行测试。这将流入我的Dependencies.Register,但对于日志记录来说已经太晚了。
这是旧模式的样子。你可以看到基本的基础架构代码不会被试图查找CreateHostBuilder的东西调用:

public class Program
{
    public static int Main(string[] args)
    {
        ConfigureLogging();

        try
        {
            CreateHostBuilder(args).Build().Run();
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "Host terminated unexpectedly");
            return 1;
        }
        finally
        {
            Log.CloseAndFlush();
        }

        return 0;
    }

    private static void ConfigureLogging()
    {
        var configuration = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            ...

        Log.Logger = new LoggerConfiguration()
            .ReadFrom.Configuration(configuration)
            ...
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(web =>
        {
            web.UseStartup<Startup>().UseSerilog();
        });
}
ghhkc1vu

ghhkc1vu1#

我个人认为有以下三种选择:
1.添加一些将由ConfigureLogging方法检查的环境变量并禁用它。
1.不再手动构建配置,而是重用构建器本身提供的配置-builder.Configuration

var builder = WebApplication.CreateBuilder(args);
ConfigureLogging(builder.Configuration);
// ...

static void ConfigureLogging(IConfigurationRoot configuration)
{
    Log.Logger = new LoggerConfiguration()
         .ReadFrom.Configuration(configuration)
         .Enrich.FromLogContext()
         ...
}

WebApplication.CreateBuilder(args)抛出应该是非常特殊的。
1.在我看来,对于这个用例最好的一个--只需要切换回generic hosting并使用前面的模式。

相关问题