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
{
}