CodeWalk

ArchUnit架构测试:守护项目架构规范

作者:我还是少年 · 2026-05-30 12:55

请详细解释ArchUnit(架构测试框架)的用法。如何用ArchUnit保护包依赖关系、分层架构、循环依赖、命名规范等?ArchUnit与传统静态分析工具有什么不同?给出常见的架构规则示例。

回答

我还是少年

ArchUnit介绍

ArchUnit是一个架构测试框架,在JUnit测试中验证代码架构是否符合预期规则。不同于PMD/SonarQube的泛化规则,ArchUnit可以定义项目特有的架构约束。

常见规则示例

@AnalyzeClasses(packages = "com.example.app")
class ArchitectureTest {

    // 1. 分层架构:controller→service→repository
    @ArchTest
    static final ArchRule layerRule = layeredArchitecture()
        .consideringAllDependencies()
        .layer("Controller").definedBy("..controller..")
        .layer("Service").definedBy("..service..")
        .layer("Repository").definedBy("..repository..")
        .whereLayer("Controller").mayNotBeAccessedByAnyLayer()
        .whereLayer("Service").mayOnlyBeAccessedByLayers("Controller")
        .whereLayer("Repository").mayOnlyBeAccessedByLayers("Service");

    // 2. 禁止循环依赖
    @ArchTest
    static final ArchRule noCycles = slices()
        .matching("..(controller|service|repository)..")
        .should().beFreeOfCycles();

    // 3. 包依赖约束
    @ArchTest
    static final ArchRule utilShouldNotDependOnService = classes()
        .that().resideInAPackage("..util..")
        .should().onlyDependOnClassesThat()
        .resideInAnyPackage("..util..", "java..", "org.apache.commons..");

    // 4. 命名规范
    @ArchTest
    static final ArchRule serviceNaming = classes()
        .that().areAnnotatedWith(Service.class)
        .should().haveSimpleNameEndingWith("Service");

    // 5. 禁止特定调用
    @ArchTest
    static final ArchRule noJpaInController = noClasses()
        .that().resideInAPackage("..controller..")
        .should().dependOnClassesThat()
        .resideInAnyPackage("..javax.persistence..", "..jpa..");

    // 6. 特定注解约束
    @ArchTest
    static final ArchRule noFieldInjection = noFields()
        .should().beAnnotatedWith(Autowired.class);
}

与静态分析工具的区别

维度ArchUnitSonarQube/PMD
定制性极高,项目特有规则通用规则
运行阶段测试时(单元测试)构建时或CI
粒度包/类/方法/字段代码行级
学习成本较高较低
典型场景分层架构、DDD限界上下文空指针、命名规范

最佳实践:ArchUnit + Checkstyle + SpotBugs组合使用,覆盖不同维度的代码质量。