Files
WCTDataMiner/tests/Gpulse.WCT.DataAnalyzer.Tests/CliTestHost.cs
Scottxjw 36c21f03dd refactor(config): 将 appsettings.json 转为嵌入资源
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-17 10:47:00 +08:00

107 lines
4.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Reflection;
using Gpulse.WCT.DataAnalyzer.Core.Infrastructure.Extensions;
using Gpulse.WCT.DataAnalyzer.Core.Infrastructure.LocalData;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace Gpulse.WCT.DataAnalyzer.Tests;
/// <summary>
/// CLI 测试宿主:用内存 SQLite 搭建与 Program.Main 一致的服务容器。
/// 每个测试实例持有独立的「本地库」/「发布库」连接与一个临时目录,互不污染。
/// </summary>
public sealed class CliTestHost : IDisposable
{
private readonly SqliteConnection _localConnection;
private readonly SqliteConnection _releaseConnection;
private readonly ServiceProvider _provider;
private readonly IServiceScope _scope;
/// <summary>测试作用域的服务提供者(与命令执行共用同一作用域)。</summary>
public IServiceProvider Services => _scope.ServiceProvider;
/// <summary>每个测试独立的临时目录,用于放置日志 fixture 文件。</summary>
public string TempDir { get; }
public WctMinerDbContext LocalDb => Services.GetRequiredService<WctMinerDbContext>();
public ReleaseDbContext ReleaseDb => Services.GetRequiredService<ReleaseDbContext>();
private CliTestHost(
SqliteConnection localConnection,
SqliteConnection releaseConnection,
ServiceProvider provider,
IServiceScope scope,
string tempDir)
{
_localConnection = localConnection;
_releaseConnection = releaseConnection;
_provider = provider;
_scope = scope;
TempDir = tempDir;
}
/// <summary>
/// 创建测试宿主:本地库/发布库各用一条独立的内存 SQLite 连接(镜像生产环境的两个库文件),
/// 并做 EnsureCreated 与种子数据初始化。
/// </summary>
public static async Task<CliTestHost> CreateAsync()
{
var tempDir = Directory.CreateTempSubdirectory("wct-tests-").FullName;
// 两个库各自独立连接,避免共享连接时 EnsureCreated 相互干扰
var localConnection = new SqliteConnection("Data Source=:memory:");
await localConnection.OpenAsync();
var releaseConnection = new SqliteConnection("Data Source=:memory:");
await releaseConnection.OpenAsync();
// 从嵌入资源加载 appsettings.json与 Program.Main 生产路径一致
var configuration = new ConfigurationBuilder()
.AddEmbeddedResourceJson(
typeof(Program).Assembly,
"Gpulse.WCT.DataAnalyzer.appsettings.json")
.AddInMemoryCollection(new Dictionary<string, string?>
{
["Database:Type"] = "sqlite",
["Parser:BatchSize"] = "1000",
})
.Build();
var services = new ServiceCollection();
services.AddSingleton<IConfiguration>(configuration);
services.AddLogging();
services.AddDbContext<WctMinerDbContext>(o => o.UseSqlite(localConnection));
services.AddDbContext<ReleaseDbContext>(o => o.UseSqlite(releaseConnection));
services.AddApplicationServices();
var provider = services.BuildServiceProvider();
// 初始化表结构与种子数据(与 Program.Main 一致)
using (var scope = provider.CreateScope())
{
var local = scope.ServiceProvider.GetRequiredService<WctMinerDbContext>();
await local.Database.EnsureCreatedAsync();
SeedData.Initialize(local);
var release = scope.ServiceProvider.GetRequiredService<ReleaseDbContext>();
await release.Database.EnsureCreatedAsync();
}
var hostScope = provider.CreateScope();
return new CliTestHost(localConnection, releaseConnection, provider, hostScope, tempDir);
}
public void Dispose()
{
_scope.Dispose();
_provider.Dispose();
_localConnection.Dispose();
_releaseConnection.Dispose();
try { Directory.Delete(TempDir, recursive: true); }
catch { /* 尽力清理临时目录 */ }
}
}