Skip to content
bitzorcas
中EN

Reference

架构测试

用程序集、项目文件、源码契约与机器可读清单守住依赖方向、模块边界、生成器、商业交付和删除门禁。

Last updated

架构测试把“代码应该怎样组织”变成提交时可执行的合同。BitzOrcas.Architecture.Tests 不只扫描程序集依赖:它还解析 .csproj、源码、JSON、YAML 和架构文档,阻止旧 mapper、运行时反射、错误的跨模块引用、失真的商业包清单和已删除浅模块重新进入主干。

它在证据链中的位置

失败通过

ADR / 架构规范

可判定规则

程序集依赖断言

项目与源码契约

Manifest / CI 契约

Architecture.Tests

修实现或更新决策

进入后续质量门禁

它证明结构仍符合已接受的设计,却不能证明 SQL、事务或消息在真实基础设施上正确;后者属于集成合同。反过来,一条 API 能跑通,也不能证明依赖方向没有退化。

当前守护面

守护面典型事实主要证据
分层依赖Domain 不依赖 Application/Infrastructure/Api编译程序集、.csproj
模块协作跨模块只经过允许的 Contracts seam项目引用图、例外登记
持久化Application 无 ORM 包;聚合与 metadata 规则成立项目 XML、源码、生成清单
AOT禁止未登记的运行时反射路径源码扫描、trim 门禁契约
生成器DI、Endpoint、Query、Persistence metadata 走编译期输出生成器源码和消费测试
商业交付catalog、Profile closure、packable 项目一致JSON、项目属性、目录扫描
Consumer模板不复制核心源码、不回引产品仓库临时消费项目与源码契约
CIJob、触发、timeout、Docker 分片、GA fail-closedWorkflow YAML 文本合同
删除门禁浅模块、旧 mapper、旧 query reflection 不得复活全局路径与 token sweep

仓库当前有大量按风险命名的规则类,例如 CsprojDependencyGraphTests、ReflectionAotGuardTests、CommercialPackageCatalogTests、DockerContractTraitTests 与 ShallowModuleDeletionGateTests。寻找现有归属比新建“万能 ArchitectureTests”更容易维护。

三种规则实现

编译后依赖规则

程序集规则回答“最终制品实际引用了谁”。Workflow 的规则会加载 BitzOrcas.Workflow.Engine,确认它不引用 SqlSugar、EF Core、Dapper、ASP.NET Core 或任何 Workflow adapter。这种检查比命名约定更接近最终二进制事实。

[Theory]
[InlineData("BitzOrcas.Workflow.Engine")]
public void WorkflowEngine_ShouldNotReferenceAdapters(string assemblyName)
{
// 读取编译后直接依赖,避免只看源码 using 得出错误结论。
var references = Assembly.Load(assemblyName)
.GetReferencedAssemblies()
.Select(item => item.Name)
.ToArray();
// 逐项写出禁止引用,使失败能直接指出被破坏的边界。
references.ShouldNotContain("SqlSugar");
references.ShouldNotContain("Microsoft.EntityFrameworkCore");
references.ShouldNotContain("BitzOrcas.Workflow.EfCore");
}

项目图与机器可读合同

CsprojDependencyGraphTests 解析所有适用的 .csproj,区分 ProjectReference 与 PackageReference,并读取显式例外登记。它能发现 Application 直接引用 ORM 包、Contracts 反向引用实现层、模块 A 直接引用模块 B 的 Application 等问题。

var project = XDocument.Load(projectPath);
// ProjectReference 决定内部层级方向;PackageReference 负责识别 ORM 泄漏。
var projectReferences = project.Descendants("ProjectReference")
.Select(node => node.Attribute("Include")?.Value)
.Where(value => value is not null)
.ToArray();
// 此处只表达 Application→Infrastructure 红线;其他层级由各自规则负责。
projectReferences.ShouldNotContain(path =>
path!.Contains(".Infrastructure", StringComparison.Ordinal));

源码与删除门禁

有些合同无法从程序集还原,例如“指定命令必须使用状态流转模板”“旧目录必须不存在”“CI 必须保留 13 个 Docker 分片”。这时规则读取源码或 Workflow 文件,并给出完整违规路径。源码 token 适合守住明确、稳定的结构事实,不适合推断复杂语义。

运行与缩小范围

Terminal window
# 合并前运行完整架构规则集。
dotnet test tests/BitzOrcas.Architecture.Tests --configuration Release
# 只验证 CI 质量门禁合同;类名 filter 比方法片段更稳定。
dotnet test tests/BitzOrcas.Architecture.Tests \
--configuration Release \
--filter 'FullyQualifiedName~CiQualityGateTests'

规则依赖 Release 编译制品时,不要拿旧的 bin/Debug 结果解释失败。使用 --no-build 前必须确认同一 Commit、同一 Configuration 已完成构建。

新增规则的完整步骤

  1. 写出被防止的具体回归,例如“Platform Application 不得 PackageReference ORM”,不要写“架构要干净”。
  2. 找到权威 ADR、约束或机器可读清单;如果决策尚未存在,先补决策。
  3. 选择最接近事实的证据:程序集、项目 XML、manifest、源码路径或 CI YAML。
  4. 让测试在违规夹具或临时改动上失败,确认不是永远为绿的断言。
  5. 输出全部 offender、规则原因和修复方向,不只返回 false。
  6. 若确有例外,登记 owner、理由和退出条件;不要把宽泛目录加入 allowlist。
  7. 运行定向规则、完整 Architecture.Tests,再运行所属业务测试。

失败定位

先看失败类名,它通常已经表达归属。依赖图失败时检查 offending .csproj 和例外清单;源码门禁失败时检查路径是否移动、语义是否变化;manifest 失败时同时比较清单生产者与消费者。只有架构决策真的改变时,才同步修改规范、测试和实现。

评审清单

  • 规则名表达业务/架构事实,而不是实现动作;
  • 扫描范围覆盖新增模块,但排除项明确;
  • 失败消息列出所有 offender 与权威规则;
  • Windows/Linux 路径分隔和大小写差异已考虑;
  • 例外是精确条目,不是目录级永久豁免;
  • 结构测试没有冒充运行时、性能或安全证明;
  • 修改后执行全局 rg/find sweep,预期旧模式结果为零。

另见

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%