272 lines
9.8 KiB
Markdown
272 lines
9.8 KiB
Markdown
# 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配置扩展
|
||
```csharp
|
||
// 扩展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注释配置
|
||
```csharp
|
||
// 在csproj中启用XML文档生成
|
||
<PropertyGroup>
|
||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||
<NoWarn>$(NoWarn);1591</NoWarn>
|
||
</PropertyGroup>
|
||
```
|
||
|
||
### 2. 集成测试组件
|
||
|
||
#### WebApplicationFactory配置
|
||
```csharp
|
||
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");
|
||
});
|
||
});
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 集成测试基类
|
||
```csharp
|
||
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. 缓存预热组件
|
||
|
||
#### 缓存预热服务接口
|
||
```csharp
|
||
public interface ICacheWarmupService
|
||
{
|
||
Task WarmupAsync(CancellationToken cancellationToken = default);
|
||
Task WarmupHotGoodsAsync(int count, CancellationToken cancellationToken = default);
|
||
Task WarmupSystemConfigAsync(CancellationToken cancellationToken = default);
|
||
}
|
||
```
|
||
|
||
#### 缓存预热后台服务
|
||
```csharp
|
||
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, "缓存预热过程中发生错误,但不影响系统启动");
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 缓存预热配置
|
||
```csharp
|
||
public class CacheWarmupOptions
|
||
{
|
||
public int HotGoodsCount { get; set; } = 100;
|
||
public bool EnableWarmup { get; set; } = true;
|
||
public int WarmupDelaySeconds { get; set; } = 5;
|
||
}
|
||
```
|
||
|
||
## Data Models
|
||
|
||
### 缓存预热配置模型
|
||
```csharp
|
||
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;
|
||
}
|
||
```
|
||
|
||
### 预热结果模型
|
||
```csharp
|
||
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进行集成测试:
|
||
|
||
```csharp
|
||
[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}**
|