【免费下载链接】ArchUnitPython
ArchUnitPython is an architecture testing library. Specify and ensure architecture rules in your Python app. Easy setup and pipeline integration.
ArchUnitPython 是一款 Python 架构测试(Architecture Testing)库,本教程带你用project_layers()快速声明 Clean Architecture 与分层依赖规则,把"高层不能依赖底层"这类架构约束变成 CI 里自动运行的测试。
为什么需要架构测试?
代码评审能拦住一部分"controllers 直接 new 了一个数据库连接"的坏味道,但拦不住下一次。把架构规则写成可执行的测试后:
- ✅ 规则常驻在测试套件里,每次提交自动校验
- ✅ 违规时直接输出具体是哪条文件依赖,定位飞快
- ✅ 架构决策被"版本化"进代码库,新人一看测试就懂设计意图
ArchUnitPython 零运行时依赖(纯标准库),pip install archunitpython即装即用,兼容 pytest、unittest 及任何测试框架。
先认识示例项目的分层结构
下面所有例子基于这样的项目布局(顶层包放在src/下):
| 目录 | 层名 | 职责 |
|---|---|---|
src/presentation/ | 表现层 | 控制器、API 路由 |
src/business/ | 业务层 | 领域逻辑 |
src/database/ | 数据层 | 持久化、ORM 访问 |
Clean Architecture 的核心约束很直白:依赖只能向内指向—— presentation → business → database,反向依赖一律不允许。
仓库自带的示例工程同样遵循三层结构,可对照阅读:
- controller.py:控制器只依赖 services
- service.py:服务只依赖 models
- model.py:模型层零内部依赖
三步用 project_layers() 声明分层依赖
第一步:用 .layer() 命名你的层
project_layers()接收导入根目录(import root,即包含顶层包的目录),随后用链式调用为每一层命名。层可以用defined_by_folder()按文件夹 glob 模式定义,也可以用defined_by()按完整路径模式定义:
from archunitpython import project_layers rule = ( project_layers("src/") .layer("presentation").defined_by_folder("**/presentation/**") .layer("business").defined_by_folder("**/business/**") .layer("database").defined_by_folder("**/database/**") )💡
**可跨多级目录匹配,所以无论层嵌套多深都能命中。
第二步:用 where_layer() 声明允许谁依赖谁
命名完层后,用where_layer()进入某一层的依赖规则配置。白名单语义由may_only_depend_on_layers()表达——括号里没列出的层,一律视为违规:
.where_layer("presentation") .may_only_depend_on_layers("business") .where_layer("business") .may_only_depend_on_layers("database") .where_layer("database") .may_only_depend_on_layers() # 数据层:不允许依赖任何已命名层最后那个空参数的may_only_depend_on_layers()值得注意:底层不允许再向外依赖任何层,这正是 Clean Architecture 的"依赖指向内部"原则。
第三步:交给断言,跑起来
完整规则配上assert_passes(),就是一个标准的 pytest 用例:
from archunitpython import assert_passes, project_layers def test_clean_architecture_layers(): rule = ( project_layers("src/") .layer("presentation").defined_by_folder("**/presentation/**") .layer("business").defined_by_folder("**/business/**") .layer("database").defined_by_folder("**/database/**") .where_layer("presentation") .may_only_depend_on_layers("business") .where_layer("business") .may_only_depend_on_layers("database") .where_layer("database") .may_only_depend_on_layers() ) assert_passes(rule)测试通过即代表全项目符合分层依赖规则;任何人在错误的层里加了一行 import,CI 立刻红给你看。
白名单还是黑名单?两种规则语义
where_layer()之后有两个可选动作,语义正好相反:
| 方法 | 语义 | 适用场景 |
|---|---|---|
may_only_depend_on_layers(a, b) | 白名单:只允许依赖列出的层 | 架构收敛、想"锁死"依赖方向 |
may_not_depend_on_layers(a) | 黑名单:仅禁止依赖列出的层 | 只针对个别违规做精准封堵 |
两者也可在同一个规则里叠加使用。判断逻辑的完整实现见 layer_dependencies.py,规则构建器 API 则定义在 layers.py。
违规了会看到什么?
断言失败时,assert_passes()会输出编号清晰的违规清单,直接给出层名 + 具体文件,例如:
Found 1 architecture violation(s): 1. Layer dependency violation Layer 'presentation' depends on disallowed layer 'database' via 'src/presentation/handler.py' -> 'src/database/repository.py'输出格式化逻辑在 assertion.py 和 violation_factory.py,违规类型LayerDependencyViolation携带源层、目标层和那条具体的依赖边,修复起来不用猜。
还可以顺手用.because(...)给规则补一句"为什么",失败信息里会一并展示,方便后来的同事理解规则意图。
新手最容易踩的 3 个坑
- 导入根目录传错。
project_layers("src/")里的参数要指向包含顶层包的目录:包在src/taskboard/就传"src",包就在仓库根目录就传"."。根目录选错会导致内部 import 被误判为外部依赖,层规则悄悄漏检。 - glob 模式不命中时先自查。
defined_by_folder("**/business/**")写错路径会静默匹配不到文件,建议先用调试日志(CheckOptions的 logging 选项)确认层确实圈到了文件。 - 同层依赖不检查。两条边若起止于同一个层,规则直接跳过(见 layer_dependencies.py),层内循环依赖请搭配
have_no_cycles()规则一起使用。
规则写法与真实运行示例可参考官方测试套件 test_layers.py,它对通过、白名单违规、黑名单违规三种场景都有覆盖。
小结
用project_layers()声明 Clean Architecture 的完整套路就是三步:
layer("x").defined_by_folder(...)—— 给层命名where_layer("x").may_only_depend_on_layers(...)—— 定依赖方向assert_passes(rule)—— 让 CI 替你守门
一条规则十几行代码,换回整个团队对架构的持续保证。更多架构测试玩法(循环依赖检测、代码指标、UML 图校验等)可以翻一下项目根目录的 README.md,它涵盖了全部使用场景。
【免费下载链接】ArchUnitPython
ArchUnitPython is an architecture testing library. Specify and ensure architecture rules in your Python app. Easy setup and pipeline integration.
相关推荐
SimpMusic 现代 Android 架构指南:Clean Architecture 分层、依赖注入与多模块化实战
SimpMusic 现代 Android 架构指南:Clean Architecture 分层、依赖注入与多模块化实战 导读 本文以仓库内 AI 开发规范文档
音视频Kvaesitso 插件 SDK 2.0.0 升级迁移指南:从 SearchPluginConfig 到 QueryPluginConfig 的破坏性变更全解析
Kvaesitso 插件 SDK 2.0.0 升级迁移指南:从 SearchPluginConfig 到 QueryPluginConfig 的破坏性变更全解析
kubectl高级功能揭秘:port-forward、exec和proxy的实战应用指南
kubectl高级功能揭秘:port forward、exec和proxy的实战应用指南 kubectl作为Kubernetes集群管理的核心命令行工具,提供了
云原生
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考