名称: 架构健康函数 描述: 使用 NetArchTest 和 ArchUnitNET 的 .NET 架构测试指南。适用于执行架构边界、测试模块依赖关系、验证层约束或创建性能健康函数。包括代码生成模板。 参数提示: [范围] [–生成] [–框架 netarchtest|archunitnet] 允许工具: 读取, 写入, 全局, 搜索, 脚本, 技能, 任务
健康函数
何时使用此技能
在需要时使用此技能:
- 强制模块之间的架构边界
- 测试依赖关系是否遵循规定规则
- 验证层约束(例如,UI → 域不应依赖)
- 创建性能健康函数
- 生成架构测试代码
- 审计现有架构的违规
关键词: 健康函数,架构测试,NetArchTest,ArchUnitNET,依赖规则,层约束,架构边界,模块隔离,架构验证,性能测试
什么是健康函数?
健康函数是验证架构特征的自动化测试。它们提供客观、可重复的验证,以确保系统在演进过程中保持期望的属性。
健康函数类型
| 类型 | 验证内容 | 示例 |
|---|---|---|
| 依赖 | 组件关系 | “域不能依赖基础设施” |
| 层 | 垂直切片规则 | “控制器仅调用应用层” |
| 命名 | 约定合规性 | “处理程序必须以’Handler’结尾” |
| 性能 | 运行时特征 | “API响应在p95时小于200毫秒” |
| 循环复杂度 | 代码复杂度 | “无方法循环复杂度大于10” |
快速开始
1. 安装所需包
# 对于 NetArchTest(更简单,推荐大多数情况)
dotnet add package NetArchTest.Rules
# 对于 ArchUnitNET(更强大,Java类语法)
dotnet add package ArchUnitNET
dotnet add package ArchUnitNET.xUnit # 或 .NUnit
2. 创建测试项目
dotnet new xunit -n YourSolution.ArchitectureTests
dotnet add YourSolution.ArchitectureTests reference src/YourSolution.Domain
dotnet add YourSolution.ArchitectureTests reference src/YourSolution.Application
dotnet add YourSolution.ArchitectureTests reference src/YourSolution.Infrastructure
3. 编写第一个测试
public class DependencyTests
{
[Fact]
public void Domain_ShouldNotDependOn_Infrastructure()
{
var result = Types.InAssembly(typeof(Order).Assembly)
.ShouldNot()
.HaveDependencyOn("YourSolution.Infrastructure")
.GetResult();
Assert.True(result.IsSuccessful, result.FailingTypeNames?.FirstOrDefault());
}
}
NetArchTest 模式
NetArchTest 提供了测试架构约束的流畅API。
详细模式: 见 references/netarchtest-patterns.md
常见规则
// 依赖约束
Types.InAssembly(domainAssembly)
.ShouldNot()
.HaveDependencyOn("Microsoft.EntityFrameworkCore");
// 命名约定
Types.InAssembly(applicationAssembly)
.That()
.ImplementInterface(typeof(IRequestHandler<,>))
.Should()
.HaveNameEndingWith("Handler");
// 层隔离
Types.InNamespace("Domain")
.ShouldNot()
.HaveDependencyOnAny("Application", "Infrastructure", "Api");
ArchUnitNET 模式
ArchUnitNET 提供更表达性的规则,语法类似于Java的ArchUnit。
详细模式: 见 references/archunitnet-patterns.md
常见规则
// 定义架构层
private static readonly Architecture Architecture =
new ArchLoader().LoadAssemblies(
typeof(Order).Assembly,
typeof(OrderHandler).Assembly,
typeof(OrderRepository).Assembly
).Build();
private static readonly IObjectProvider<IType> DomainLayer =
Types().That().ResideInNamespace("Domain").As("域层");
private static readonly IObjectProvider<IType> InfrastructureLayer =
Types().That().ResideInNamespace("Infrastructure").As("基础设施层");
[Fact]
public void DomainLayer_ShouldNotDependOn_InfrastructureLayer()
{
IArchRule rule = Types().That().Are(DomainLayer)
.Should().NotDependOnAny(InfrastructureLayer);
rule.Check(Architecture);
}
依赖规则目录
模块化单体应用的常见依赖规则:
完整目录: 见 references/dependency-rules.md
模块隔离
[Fact]
public void Modules_ShouldNotCrossReference_CoreProjects()
{
var orderingCore = Types.InAssembly(typeof(Order).Assembly);
var inventoryCore = Types.InAssembly(typeof(Product).Assembly);
// Ordering.Core 不能引用 Inventory.Core
var result = orderingCore
.ShouldNot()
.HaveDependencyOn("Inventory.Core")
.GetResult();
Assert.True(result.IsSuccessful);
}
共享内核约束
[Fact]
public void SharedKernel_ShouldNotDependOn_AnyModule()
{
var sharedKernel = Types.InAssembly(typeof(Entity).Assembly);
var result = sharedKernel
.ShouldNot()
.HaveDependencyOnAny(
"Ordering", "Inventory", "Shipping", "Customers")
.GetResult();
Assert.True(result.IsSuccessful);
}
性能健康函数
测试运行时特征以确保性能标准。
详细指南: 见 references/performance-fitness.md
响应时间测试
[Fact]
public async Task Api_ShouldRespondWithin_200ms()
{
var client = _factory.CreateClient();
var stopwatch = Stopwatch.StartNew();
var response = await client.GetAsync("/api/orders/123");
stopwatch.Stop();
Assert.True(stopwatch.ElapsedMilliseconds < 200,
$"响应耗时 {stopwatch.ElapsedMilliseconds} 毫秒");
}
内存分配测试
[Fact]
public void Handler_ShouldNotAllocateExcessiveMemory()
{
var before = GC.GetTotalMemory(true);
for (int i = 0; i < 1000; i++)
{
_handler.Handle(new GetOrderQuery(Guid.NewGuid()));
}
var after = GC.GetTotalMemory(true);
var allocated = (after - before) / 1000; // 每次操作
Assert.True(allocated < 10_000, $"每次操作分配 {allocated} 字节");
}
代码生成模板
使用这些模板快速创建架构测试:
references/templates/architecture-test-template.cs- 完整测试类脚手架references/templates/performance-test-template.cs- 性能测试模式
快速模板使用
# 复制模板并定制化
cp templates/architecture-test-template.cs tests/ArchitectureTests.cs
与 CI/CD 集成
GitHub Actions 示例
- name: 运行架构测试
run: dotnet test --filter Category=Architecture
continue-on-error: false # 违规时使流水线失败
测试类别
[Trait("Category", "Architecture")]
public class DependencyTests
{
// 架构测试与单元测试分开运行
}
与事件风暴集成
健康函数强制执行通过事件风暴发现的边界:
事件风暴 → 有界上下文
↓
模块化架构 → 模块结构
↓
健康函数 → 强制执行边界
事件风暴识别有界上下文后:
- 基于上下文定义模块
- 创建模块间依赖规则
- 添加健康函数以强制执行隔离
最佳实践
- 在 CI/CD 中运行 - 合并前捕获违规
- 从关键规则开始 - 不要一开始就测试所有内容
- 清晰的失败消息 - 使违规易于理解
- 分类测试 - 与单元/集成测试分开
- 记录意图 - 解释每个规则存在的原因
- 定期审查 - 随架构演进更新规则
故障排除
常见问题
测试未找到类型:
- 检查测试项目中的程序集引用
- 验证命名空间模式与实际命名空间匹配
误报:
- 为合法依赖添加排除
- 检查通过共享包的间接依赖
性能测试不稳定:
- 测量前使用预热运行
- 在隔离环境中运行
- 使用统计显著性(多次运行)
参考资料
references/netarchtest-patterns.md- NetArchTest 使用模式references/archunitnet-patterns.md- ArchUnitNET 使用模式references/performance-fitness.md- 性能测试模式references/dependency-rules.md- 常见依赖规则目录references/templates/architecture-test-template.cs- 测试类模板references/templates/performance-test-template.cs- 性能测试模板
用户界面
当用户直接调用时,此技能分析架构健康并可选生成测试。
执行工作流
- 解析参数 - 提取范围(默认:当前目录)、
--生成标志和--框架偏好(netarchtest 或 archunitnet)。 - 分析项目结构 - 发现解决方案/项目文件、命名空间层次结构、架构风格(清洁、六边形、模块化单体、垂直切片)和类型约定。
- 评估健康 - 检查依赖规则(域不依赖基础设施)、层约束(控制器仅在表示层)和命名约定(处理程序以"Handler"结尾)。
- 生成报告 - 生成健康报告,包括摘要表、通过/失败检查、违规位置和优先级建议。
- 生成测试(如果
--generate) - 生成健康函数生成器代理以创建包含 DependencyTests、NamingConventionTests 和 StructureTests 的测试项目。 - 建议 CI/CD 集成 - 推荐将架构测试添加到 GitHub Actions 工作流。
版本历史
- v1.0.0 (2025-12-22):初始发布
- NetArchTest 和 ArchUnitNET 模式
- 依赖规则目录
- 性能健康函数
- 代码生成模板
- CI/CD 集成指南
最后更新
日期: 2025-12-22 模型: claude-opus-4-5-20251101