我使用Program.cs
和Startup.cs
运行我的asp.net core 7 web api
应用程序。我已经使用CustomWebApplicationFactory<TStartup>
编写了我的Integration Tests
。所有都按预期工作。
现在我决定放弃Startup.cs
,所以我把所有的Startup.cs
逻辑都移到了Program.cs
里面,我的Program.cs
看起来像,
try
{
//Read Configuration from appSettings
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
//Initialize Logger
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(config)
.CreateLogger();
Log.Information($"Starting {typeof(Program).Assembly.FullName}");
var builder = WebApplication.CreateBuilder();
builder.Host.UseSerilog();//Uses Serilog instead of default .NET Logger
builder.WebHost.ConfigureKestrel(options =>
{
// Set properties and call methods on options
options.AddServerHeader = false;
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier);
//JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("role", ClaimTypes.Role);
builder.Services.AddHttpContextAccessor()
.AddApiClients(builder.Configuration)
.AddApplicationServices(builder.Configuration)
.AddMemoryCache()
.AddResponseCompression()
.AddApiControllersAndBehavior()
.AddApiVersion()
.AddApiAuthenticationAndAuthorization(builder.Configuration)
.AddSwagger(builder.Configuration)
.AddApplicationServices()
.AddCors(options =>
{
options.AddPolicy("AppClients", policyBuilder => policyBuilder.WithOrigins(builder.Configuration.GetValue<string>("WebClient"))
.AllowAnyHeader()
.AllowAnyMethod());
})
//.AddHttpLogging(options =>
//{
// options.LoggingFields = HttpLoggingFields.All;
//})
.AddFeatureManagement()
.UseDisabledFeaturesHandler(new DisabledFeatureHandler());
var consoleLogging = new ConsoleLogging(builder.Configuration.GetValue<bool>("EnableConsoleLogging"));
builder.Services.AddSingleton(consoleLogging);
var commandsConnectionString = new CommandConnectionString(builder.Configuration.GetConnectionString("CommandsConnectionString"));
builder.Services.AddSingleton(commandsConnectionString);
var queriesConnectionString = new QueryConnectionString(builder.Configuration.GetConnectionString("QueriesConnectionString"));
builder.Services.AddSingleton(queriesConnectionString);
if (builder.Environment.IsDevelopment())
{
//builder.Services.AddScoped<BaseReadContext, AppInMemoryReadContext>();
//builder.Services.AddScoped<BaseContext, AppInMemoryContext>();
builder.Services.AddScoped<BaseReadContext, AppSqlServerReadContext>();
builder.Services.AddScoped<BaseContext, AppSqlServerContext>();
builder.Services.AddMiniProfilerServices();
}
else
{
builder.Services.AddScoped<BaseReadContext, AppSqlServerReadContext>();
builder.Services.AddScoped<BaseContext, AppSqlServerContext>();
}
var app = builder.Build();
app.UseMiddleware<ExceptionHandler>()
//.UseHttpLogging()
.UseSecurityHeaders(SecurityHeadersDefinitions.GetHeaderPolicyCollection(builder.Environment.IsDevelopment()))
.UseHttpsRedirection()
.UseResponseCompression();
if (builder.Environment.IsDevelopment())
{
app.UseMiniProfiler()
.UseSwagger()
.UseSwaggerUI(options =>
{
foreach (var description in app.Services.GetRequiredService<IApiVersionDescriptionProvider>().ApiVersionDescriptions)
{
options.SwaggerEndpoint(
$"swagger/AppOpenAPISpecification{description.GroupName}/swagger.json",
$"App API - {description.GroupName.ToUpperInvariant()}");
}
options.OAuthClientId("appswaggerclient");
options.OAuthAppName("App API");
options.OAuthUsePkce();
options.RoutePrefix = string.Empty;
options.DefaultModelExpandDepth(2);
options.DefaultModelRendering(ModelRendering.Model);
options.DocExpansion(DocExpansion.None);
options.DisplayRequestDuration();
options.EnableValidator();
options.EnableFilter();
options.EnableDeepLinking();
options.DisplayOperationId();
});
}
app.UseRouting()
.UseCors("AppClients")
.UseAuthentication()
.UseAuthorization()
.UseRequestLocalization(options =>
{
var supportedCultures = new[] { "en", "en-IN", "en-US" };
options.SetDefaultCulture("en-IN");
options.AddSupportedCultures(supportedCultures);
options.AddSupportedUICultures(supportedCultures);
options.ApplyCurrentCultureToResponseHeaders = true;
})
.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
await app.RunAsync();
}
catch (Exception ex)
{
Log.Fatal(ex, "The Application failed to start.");
}
finally
{
Log.CloseAndFlush();
}
/// <summary>
/// Added to Make FunctionalTest Compile
/// </summary>
public partial class Program { }
这是我的CustomWebApplicationFactory<TProgram>
public class CustomWebApplicationFactory<TProgram> : WebApplicationFactory<TProgram> where TProgram : class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
var projectDir = Directory.GetCurrentDirectory();
builder.ConfigureAppConfiguration((context, conf) =>
{
conf.AddJsonFile(Path.Combine(projectDir, "appsettings.Test.json"));
});
builder.UseEnvironment("Testing");
builder.ConfigureTestServices(async services =>
{
services.AddAuthentication("Test")
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>("Test", options => { });
services.AddScoped(_ => AuthClaimsProvider.WithMasterClaims());
var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(BaseContext));
if (descriptor != null)
{
services.Remove(descriptor);
}
descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(BaseReadContext));
if (descriptor != null)
{
services.Remove(descriptor);
}
descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(ITenantService));
if (descriptor != null)
{
services.Remove(descriptor);
services.AddTransient<ITenantService, TestTenantService>();
}
var connectionStringBuilder = new SqliteConnectionStringBuilder { DataSource = ":memory:" };
var connection = new SqliteConnection(connectionStringBuilder.ToString());
var dbContextOptions = new DbContextOptionsBuilder<AppSqliteInMemoryContext>()
.UseSqlite(connection)
.Options;
services.AddScoped<BaseContext>(options => new AppSqliteInMemoryContext(dbContextOptions));
var dbContextReadOptions = new DbContextOptionsBuilder<AppSqliteInMemoryReadContext>()
.UseSqlite(connection)
.Options;
services.AddScoped<BaseReadContext>(options => new AppSqliteInMemoryReadContext(
dbContextReadOptions, options.GetRequiredService<ITenantService>()));
await connection.CloseAsync();
var sp = services.BuildServiceProvider();
using var scope = sp.CreateScope();
var scopedServices = scope.ServiceProvider;
var db = scopedServices.GetRequiredService<BaseContext>();
var logger = scopedServices.GetRequiredService<ILogger<CustomWebApplicationFactory<Program>>>();
try
{
await db.Database.OpenConnectionAsync();
await db.Database.EnsureCreatedAsync();
await DatabaseHelper.InitialiseDbForTests(db);
}
catch (Exception ex)
{
logger.LogError(ex, $"An error occurred seeding the database with test data. Error: {ex.Message}");
throw;
}
});
}
}
这是我的Integration Test
public class GetByIdTests : IClassFixture<CustomWebApplicationFactory<Program>>
{
private readonly HttpClient _client;
public GetByIdTests(CustomWebApplicationFactory<Program> factory)
{
//factory.ClientOptions.BaseAddress = new Uri("https://localhost:44367");
_client = factory.CreateClient(new WebApplicationFactoryClientOptions
{
BaseAddress = new Uri("https://localhost:44367"),
AllowAutoRedirect = false
});
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Test");
_client.DefaultRequestHeaders.Add("x-api-version", "1.0");
}
[Fact]
public async Task GetById_ReturnsExpectedResponse_ForMasterUser()
{
var id = Guid.Parse("6B4DFE8A-2FCB-4716-94ED-4D63BF9351C6");
using var request = new HttpRequestMessage(HttpMethod.Get, $"/api/branches/{id}");
var response = await _client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
}
}
我已经按照official docs中提到的所有步骤进行了测试。但是当我运行测试时,我一直得到404未找到。
这是错误屏幕截图,
你能帮我看看我做错了什么吗?
2条答案
按热度按时间wj8zmpe11#
在集成测试类中,您使用显式BaseAddress配置HttpClient。
但据我所知,您没有在CustomWebApplicationFactory中提供此配置。要在没有环境变量的情况下以编程方式执行此操作,您可以调用IHostWebAplicationBuilder上的UseUrls()方法
k4ymrczo2#
从
Startup.cs
到Program.cs
的这种移动在我的积压工作中已经有很长时间了,每次我尝试的时候,我在测试中都以404
NotFound
结束。最后我想明白了。这就是办法。
我正在将我的
Program.cs
与eshoponwebProgram.cs
逐行比较,并注意到我的CreateBuilder()
中缺少args
。在我的
Program.cs
中,我只是将var builder = WebApplication.CreateBuilder();
到
var builder = WebApplication.CreateBuilder(args);
//在此处添加了参数它开始起作用了。
我的
Program.cs
缺少args
的原因是我们的sonar qube
扫描仪突出显示了args
的security risk
,因此我们在项目针对ASP.NET Core 3.1
时删除了它,现在当项目针对ASP.NET Core 6
或更高版本时,它使我们的测试失败。