如何用单个ArchUnit测试同时校验类和方法的事务注解规则?
简化ArchUnit测试的方案
当然可以把这4个测试合并成单个测试,借助ArchUnit的规则组合能力就能实现。下面是具体的实现思路和代码示例:
核心规则拆解与合并
规则1:Spring @Transactional的约束
- 类层面:被
@org.springframework.transaction.annotation.Transactional标注的类,必须同时标注@org.springframework.stereotype.Service - 方法层面:被
@org.springframework.transaction.annotation.Transactional标注的方法,必须定义在被@Service标注的类中
规则2:禁止使用Jakarta @Transactional
- 禁止任何类标注
@jakarta.transaction.Transactional - 禁止任何方法标注
@jakarta.transaction.Transactional
将以上4项子规则通过ArchRuleDefinition.allOf()组合,即可在单个测试中完成全部校验:
import com.tngtech.archunit.core.domain.JavaClasses; import com.tngtech.archunit.core.importer.ClassFileImporter; import com.tngtech.archunit.lang.ArchRule; import com.tngtech.archunit.lang.syntax.ArchRuleDefinition; import org.junit.jupiter.api.Test; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import static com.tngtech.archunit.lang.conditions.ArchConditions.alwaysFalse; import static com.tngtech.archunit.lang.syntax.ConditionPredicates.describedAs; class TransactionalArchRulesTest { // 替换为你要扫描的基础包路径 private static final JavaClasses CLASSES = new ClassFileImporter().importPackages("your.app.base.package"); @Test void enforceAllTransactionalRules() { // Spring @Transactional类的约束 ArchRule springTxClassRule = ArchRuleDefinition.classes() .that().areAnnotatedWith(Transactional.class) .should().beAnnotatedWith(Service.class); // Spring @Transactional方法的约束 ArchRule springTxMethodRule = ArchRuleDefinition.methods() .that().areAnnotatedWith(Transactional.class) .should().beDeclaredInClassesThat().areAnnotatedWith(Service.class); // 禁止类使用Jakarta @Transactional ArchRule forbidJakartaTxClassRule = ArchRuleDefinition.classes() .that().areAnnotatedWith(jakarta.transaction.Transactional.class) .should(describedAs("not use jakarta.transaction.Transactional annotation"), alwaysFalse()); // 禁止方法使用Jakarta @Transactional ArchRule forbidJakartaTxMethodRule = ArchRuleDefinition.methods() .that().areAnnotatedWith(jakarta.transaction.Transactional.class) .should(describedAs("not use jakarta.transaction.Transactional annotation"), alwaysFalse()); // 组合所有规则并执行校验 ArchRule combinedRule = ArchRuleDefinition.allOf( springTxClassRule, springTxMethodRule, forbidJakartaTxClassRule, forbidJakartaTxMethodRule ); combinedRule.check(CLASSES); } }
这样单个测试就能覆盖所有要求的校验逻辑,若有规则违反,测试会清晰标注是类还是方法层面的问题,便于快速定位。
内容的提问来源于stack exchange,提问作者Dónal
相关产品推荐
相关产品推荐

