9.8 KiB
Design Document: 高级功能迁移
Overview
本设计文档描述阶段8高级功能的实现方案,包括API文档完善、集成测试覆盖和缓存预热机制。这些功能将确保迁移后的系统具备完整的文档、可靠的测试覆盖和良好的启动性能。
Architecture
整体架构
┌─────────────────────────────────────────────────────────────┐
│ HoneyBox.Api │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
│ │ Swagger/OpenAPI │ │ Controllers │ │ Startup │ │
│ │ Documentation │ │ (XML Comments) │ │ Services │ │
│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
│ │ │
│ ┌────────▼───────┐ │
│ │ CacheWarmup │ │
│ │ HostedService │ │
│ └────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────▼───────────────────────────────┐
│ HoneyBox.Tests │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
│ │ Integration │ │ WebApplication │ │ Test │ │
│ │ Tests │ │ Factory │ │ Database │ │
│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
Components and Interfaces
1. API文档组件
OpenAPI配置扩展
// 扩展OpenAPI配置,添加JWT认证和中文描述
public static class OpenApiExtensions
{
public static IServiceCollection AddHoneyBoxOpenApi(this IServiceCollection services)
{
services.AddOpenApi(options =>
{
options.AddDocumentTransformer((document, context, ct) =>
{
document.Info.Title = "HoneyBox API";
document.Info.Version = "v1";
document.Info.Description = "友达赏抽奖系统API文档";
return Task.CompletedTask;
});
});
return services;
}
}
XML注释配置
// 在csproj中启用XML文档生成
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>
2. 集成测试组件
WebApplicationFactory配置
public class HoneyBoxWebApplicationFactory : WebApplicationFactory<Program>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
// 移除生产数据库配置
var descriptor = services.SingleOrDefault(
d => d.ServiceType == typeof(DbContextOptions<HoneyBoxDbContext>));
if (descriptor != null)
services.Remove(descriptor);
// 使用内存数据库
services.AddDbContext<HoneyBoxDbContext>(options =>
{
options.UseInMemoryDatabase("TestDb");
});
});
}
}
集成测试基类
public abstract class IntegrationTestBase : IClassFixture<HoneyBoxWebApplicationFactory>
{
protected readonly HttpClient Client;
protected readonly HoneyBoxWebApplicationFactory Factory;
protected IntegrationTestBase(HoneyBoxWebApplicationFactory factory)
{
Factory = factory;
Client = factory.CreateClient();
}
protected async Task<string> GetAuthTokenAsync(int userId = 1)
{
// 生成测试用JWT Token
}
}
3. 缓存预热组件
缓存预热服务接口
public interface ICacheWarmupService
{
Task WarmupAsync(CancellationToken cancellationToken = default);
Task WarmupHotGoodsAsync(int count, CancellationToken cancellationToken = default);
Task WarmupSystemConfigAsync(CancellationToken cancellationToken = default);
}
缓存预热后台服务
public class CacheWarmupHostedService : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<CacheWarmupHostedService> _logger;
private readonly CacheWarmupOptions _options;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("开始缓存预热...");
using var scope = _serviceProvider.CreateScope();
var warmupService = scope.ServiceProvider.GetRequiredService<ICacheWarmupService>();
try
{
await warmupService.WarmupAsync(stoppingToken);
_logger.LogInformation("缓存预热完成");
}
catch (Exception ex)
{
_logger.LogError(ex, "缓存预热过程中发生错误,但不影响系统启动");
}
}
}
缓存预热配置
public class CacheWarmupOptions
{
public int HotGoodsCount { get; set; } = 100;
public bool EnableWarmup { get; set; } = true;
public int WarmupDelaySeconds { get; set; } = 5;
}
Data Models
缓存预热配置模型
public class CacheWarmupOptions
{
/// <summary>
/// 热门商品预热数量
/// </summary>
public int HotGoodsCount { get; set; } = 100;
/// <summary>
/// 是否启用预热
/// </summary>
public bool EnableWarmup { get; set; } = true;
/// <summary>
/// 预热延迟秒数(等待系统完全启动)
/// </summary>
public int WarmupDelaySeconds { get; set; } = 5;
}
预热结果模型
public class WarmupResult
{
public bool Success { get; set; }
public int ItemsWarmed { get; set; }
public TimeSpan Duration { get; set; }
public string? ErrorMessage { get; set; }
}
Correctness Properties
A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.
Property 1: API文档完整性
For any 已迁移的控制器端点,OpenAPI规范中应该包含该端点的定义,包括路径、方法、参数和响应类型。 Validates: Requirements 1.1, 1.5
Property 2: API文档中文描述
For any OpenAPI规范中的端点定义,应该包含非空的summary或description字段。 Validates: Requirements 1.3
Property 3: 集成测试响应格式一致性
For any API响应,其JSON结构应该包含status、msg、data三个字段,且status为整数类型。 Validates: Requirements 2.6
Property 4: 缓存预热异步性
For any 系统启动过程,缓存预热应该在后台异步执行,系统启动时间不应因预热数据量增加而显著增长。 Validates: Requirements 3.3
Error Handling
API文档错误处理
- 如果XML注释文件不存在,系统应该正常启动但记录警告日志
- 如果OpenAPI配置失败,应该记录错误但不影响API正常运行
集成测试错误处理
- 测试数据库初始化失败时,应该提供清晰的错误信息
- 测试超时时,应该记录详细的执行状态
缓存预热错误处理
- 数据库连接失败时,记录错误但继续系统启动
- 单个数据项预热失败时,跳过该项继续预热其他数据
- Redis连接失败时,记录警告并跳过预热
Testing Strategy
单元测试
- 测试缓存预热服务的各个方法
- 测试配置选项的默认值和边界值
集成测试
使用xUnit和WebApplicationFactory进行集成测试:
[Fact]
public async Task GetGoodsList_ShouldReturnSuccess()
{
// Arrange
var client = _factory.CreateClient();
// Act
var response = await client.GetAsync("/api/goods_list?type=1");
// Assert
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<ApiResponse<object>>(content);
Assert.Equal(1, result.Status);
}
属性测试
使用FsCheck进行属性测试,验证:
- API响应格式一致性
- 缓存预热的异步性
测试配置
- 最小100次迭代用于属性测试
- 使用内存数据库进行集成测试
- 测试标签格式: Feature: advanced-features, Property {number}: {property_text}