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.json
和appsettings.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();
});
}
1条答案
按热度按时间ghhkc1vu1#
我个人认为有以下三种选择:
1.添加一些将由
ConfigureLogging
方法检查的环境变量并禁用它。1.不再手动构建配置,而是重用构建器本身提供的配置-
builder.Configuration
:WebApplication.CreateBuilder(args)
抛出应该是非常特殊的。1.在我看来,对于这个用例最好的一个--只需要切换回generic hosting并使用前面的模式。