using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.TestHost; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Xunit; using YarpGateway.Data; using YarpGateway.DynamicProxy; using YarpGateway.Services; namespace YarpGateway.Tests.Integration; /// /// 集成测试基类 /// 提供 WebApplicationFactory 和 HttpClient 的共享实例 /// public class TestFixture : IAsyncLifetime { public WebApplicationFactory Factory { get; private set; } = null!; public HttpClient Client { get; private set; } = null!; public IServiceProvider Services { get; private set; } = null!; public async Task InitializeAsync() { Factory = new WebApplicationFactory() .WithWebHostBuilder(builder => { builder.UseEnvironment("Testing"); builder.ConfigureServices(services => { // 移除 PostgreSQL 数据库上下文 var descriptor = services.SingleOrDefault( d => d.ServiceType == typeof(IDbContextFactory)); if (descriptor != null) { services.Remove(descriptor); } var dbContextDescriptor = services.SingleOrDefault( d => d.ServiceType == typeof(DbContextOptions)); if (dbContextDescriptor != null) { services.Remove(dbContextDescriptor); } // 使用内存数据库替换 services.AddDbContextFactory(options => { options.UseInMemoryDatabase($"YarpGateway_Test_{Guid.NewGuid()}"); }); // 移除 PgSqlConfigChangeListener(因为内存数据库不支持 NOTIFY) var listenerDescriptor = services.SingleOrDefault( d => d.ServiceType == typeof(Microsoft.Extensions.Hosting.IHostedService) && d.ImplementationType == typeof(PgSqlConfigChangeListener)); if (listenerDescriptor != null) { services.Remove(listenerDescriptor); } // 移除 Redis 相关服务(测试环境不需要) services.RemoveAll(typeof(StackExchange.Redis.IConnectionMultiplexer)); services.RemoveAll(typeof(IRedisConnectionManager)); // 添加内存缓存 services.AddMemoryCache(); // 确保 RouteCache 被正确注册 services.RemoveAll(typeof(IRouteCache)); services.AddSingleton(); }); }); Client = Factory.CreateClient(); Services = Factory.Services; // 初始化数据库种子数据 await SeedDatabaseAsync(); } public async Task DisposeAsync() { Client?.Dispose(); if (Factory != null) { await Factory.DisposeAsync(); } } /// /// 获取新的数据库上下文实例 /// public GatewayDbContext CreateDbContext() { var factory = Services.GetRequiredService>(); return factory.CreateDbContext(); } /// /// 获取 RouteCache 实例 /// public IRouteCache GetRouteCache() { return Services.GetRequiredService(); } /// /// 获取 DynamicProxyConfigProvider 实例 /// public DynamicProxyConfigProvider GetConfigProvider() { return Services.GetRequiredService(); } /// /// 获取内存缓存实例 /// public IMemoryCache GetMemoryCache() { return Services.GetRequiredService(); } /// /// 重新加载配置 /// public async Task ReloadConfigurationAsync() { var routeCache = GetRouteCache(); await routeCache.ReloadAsync(); var configProvider = GetConfigProvider(); configProvider.UpdateConfig(); } /// /// 初始化数据库种子数据 /// private async Task SeedDatabaseAsync() { using var scope = Services.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService(); // 添加测试租户 await TestData.SeedTenantsAsync(dbContext); // 添加测试路由 await TestData.SeedRoutesAsync(dbContext); // 添加测试集群和目标 await TestData.SeedClustersAsync(dbContext); await dbContext.SaveChangesAsync(); // 初始化 RouteCache var routeCache = scope.ServiceProvider.GetRequiredService(); await routeCache.InitializeAsync(); // 初始化配置提供程序 var configProvider = scope.ServiceProvider.GetRequiredService(); configProvider.UpdateConfig(); } } /// /// 集合定义,确保使用 TestFixture 的测试不会并行执行 /// [CollectionDefinition("Integration Tests")] public class IntegrationTestCollection : ICollectionFixture { }