- 新增 GatewayAggregate 领域实体 (GwTenant, GwTenantRoute, GwServiceInstance) - 新增 IRouteStore, RouteStore, IInstanceStore, InstanceStore - 新增 IRouteManager, RouteManager - 合并 GatewayDbContext 到 PlatformDbContext - 统一 Extensions.AddPlatformCore 注册所有服务
5.7 KiB
5.7 KiB
测试模式
分析日期: 2026-02-28
测试框架
状态: 此仓库中目前不存在测试项目。
预期框架(未实现)
基于项目结构和依赖,测试项目应使用:
- 测试运行器: xUnit(.NET 标准)
- 模拟: Moq 或 NSubstitute
- 内存数据库:
Microsoft.EntityFrameworkCore.InMemory用于 DbContext 测试 - 断言: FluentAssertions(可选,用于可读断言)
建议的项目结构
Fengling.Platform.Tests/
├── Fengling.Platform.Tests.csproj
├── Unit/
│ ├── TenantManagerTests.cs
│ ├── TenantStoreTests.cs
│ └── PlatformDbContextTests.cs
├── Integration/
│ └── TenantRepositoryTests.cs
└── Usings.cs
测试文件组织
位置
- 模式: 单独测试项目(
Fengling.Platform.Tests/) - 结构: 镜像源项目结构
命名
- 测试类:
{类名}Tests或{类名}Tests - 测试方法:
{方法名}_{场景}_{预期结果}
测试结构
套件组织(预期模式)
public class TenantManagerTests
{
private readonly ITenantManager _tenantManager;
private readonly Mock<ITenantStore> _storeMock;
public TenantManagerTests()
{
_storeMock = new Mock<ITenantStore>();
_tenantManager = new TenantManager(_storeMock.Object);
}
[Fact]
public async Task FindByIdAsync_WithValidId_ReturnsTenant()
{
// Arrange
var tenantId = 1L;
var expectedTenant = new Tenant { Id = tenantId, Name = "Test" };
_storeMock.Setup(s => s.FindByIdAsync(tenantId, It.IsAny<CancellationToken>()))
.ReturnsAsync(expectedTenant);
// Act
var result = await _tenantManager.FindByIdAsync(tenantId);
// Assert
Assert.NotNull(result);
Assert.Equal(tenantId, result.Id);
}
}
模拟
框架: Moq
要模拟:
ITenantStore-TenantManager的依赖PlatformDbContext- 用于仓储测试
模式
// 带参数的模拟设置
_storeMock.Setup(s => s.FindByIdAsync(tenantId, It.IsAny<CancellationToken>()))
.ReturnsAsync(expectedTenant);
// 空返回模拟
_storeMock.Setup(s => s.FindByIdAsync(It.IsAny<long?>(), It.IsAny<CancellationToken>()))
.ReturnsAsync((Tenant?)null);
// 验证调用
_storeMock.Verify(s => s.CreateAsync(It.IsAny<Tenant>(), It.IsAny<CancellationToken>()), Times.Once);
不要模拟:
Tenant实体(使用真实实例)- 值类型和简单 DTO
测试夹具和工厂
测试数据
public static class TenantFixture
{
public static Tenant CreateValidTenant(long id = 1)
=> new Tenant
{
Id = id,
TenantCode = "TEST",
Name = "Test Tenant",
ContactName = "John Doe",
ContactEmail = "john@test.com",
Status = TenantStatus.Active,
CreatedAt = DateTime.UtcNow
};
public static IEnumerable<Tenant> CreateTenantCollection(int count)
=> Enumerable.Range(1, count)
.Select(i => CreateValidTenant(i));
}
位置
Tests/Fixtures/或Tests/Factories/
测试类型
单元测试
- 范围: 隔离的单个类
- 目标:
TenantManager- CRUD 操作 - 目标:
TenantStore- 数据访问方法 - 目标: 实体验证逻辑
- 方法: 模拟依赖,隔离测试
集成测试
- 范围: 使用
PlatformDbContext的数据库操作 - 方法:
- 使用
InMemoryDatabase隔离 - 使用
DbContextOptionsBuilder+UseInMemoryDatabase
- 使用
public class PlatformDbContextTests
{
private readonly PlatformDbContext _context;
public PlatformDbContextTests()
{
var options = new DbContextOptionsBuilder<PlatformDbContext>()
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
.Options;
_context = new PlatformDbContext(options);
}
}
端到端测试
- 不适用: 这是一个库/项目,不是应用程序
常见模式
异步测试
[Fact]
public async Task GetAllAsync_ReturnsAllTenants()
{
// Arrange
var tenants = new List<Tenant> { CreateValidTenant(), CreateValidTenant(2) };
_storeMock.Setup(s => s.GetAllAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(tenants);
// Act
var result = await _tenantManager.GetAllAsync();
// Assert
Assert.Equal(2, result.Count);
}
错误测试
[Fact]
public async Task CreateAsync_WithDuplicateTenantCode_ReturnsFailure()
{
// Arrange
var tenant = CreateValidTenant();
_storeMock.Setup(s => s.FindByTenantCodeAsync(tenant.TenantCode, It.IsAny<CancellationToken>()))
.ReturnsAsync(tenant); // 模拟已存在的租户
// Act
var result = await _tenantManager.CreateAsync(tenant);
// Assert
Assert.False(result.Succeeded);
}
空参数测试
[Fact]
public async Task FindByIdAsync_WithNullId_ReturnsNull()
{
// Act
var result = await _tenantManager.FindByIdAsync(null);
// Assert
Assert.Null(result);
}
覆盖率
要求
- 未强制 - 目前未定义覆盖率目标
建议目标
- 最低: 领域逻辑 70%
- 目标: 关键路径(租户 CRUD)80%
查看覆盖率
dotnet test --collect:"XPlat Code Coverage"
# 或使用 coverlet
dotnet test /p:CollectCoverage=true /p:Threshold=80
运行测试
命令(预期)
dotnet test # 运行所有测试
dotnet test --filter "FullyQualifiedName~TenantManagerTests" # 运行特定类
dotnet test --verbosity normal # 详细输出
dotnet test --collect:"XPlat Code Coverage" # 带覆盖率
测试分析: 2026-02-28