如何编写ArchUnit规则校验@SpringBootApplication类的多项规范
如何编写ArchUnit规则校验@SpringBootApplication类的多项规范
我来帮你把剩下的ArchUnit规则补全,刚好能覆盖你提到的所有校验点!咱们一步步拆解每个要求,最后整合出完整的测试规则。
首先,你已经实现的「类名必须以Application结尾」规则完全没问题,接下来咱们搞定剩下三个核心要求:
1. 确保项目中只有一个@SpringBootApplication类
这个很直接,用haveSize(1)就能校验,只要项目中这类类的数量不是1,测试就会抛出明确的错误。
2. 校验类是public修饰的
ArchUnit提供了现成的断言bePublic(),直接链式调用即可完成校验。
3. 校验类除了标准main方法外无其他内容
这个需要自定义一个ArchCondition做细致检查,要确保:
- 没有任何字段/常量
- 没有自定义构造方法(Java自动生成的默认构造可以保留,毕竟普通类无法完全移除默认构造)
- 只有一个方法,且这个方法是标准的
public static void main(String[] args)
先写这个自定义条件:
private static final ArchCondition<JavaClass> ONLY_HAVE_VALID_MAIN_METHOD = new ArchCondition<>("only contain one public static void main method (with String[] args) and no other custom members") { @Override public void check(JavaClass javaClass, ConditionEvents events) { // 检查是否存在字段/常量 if (!javaClass.getFields().isEmpty()) { events.add(SimpleConditionEvent.violated( javaClass, javaClass.getName() + " contains unexpected fields: " + javaClass.getFields() )); } // 检查是否存在自定义构造方法(排除Java自动生成的默认构造) long customConstructors = javaClass.getConstructors().stream() .filter(constructor -> !constructor.isDefaultConstructor()) .count(); if (customConstructors > 0) { events.add(SimpleConditionEvent.violated( javaClass, javaClass.getName() + " contains custom constructors: " + javaClass.getConstructors() )); } // 检查方法数量和main方法的合法性 List<JavaMethod> methods = javaClass.getMethods(); if (methods.size() != 1) { events.add(SimpleConditionEvent.violated( javaClass, javaClass.getName() + " has " + methods.size() + " methods (expected exactly 1 main method)" )); } else { JavaMethod mainMethod = methods.get(0); boolean isValidMain = mainMethod.isPublic() && mainMethod.isStatic() && mainMethod.getReturnType().isVoid() && mainMethod.getName().equals("main") && mainMethod.getParameters().size() == 1 && mainMethod.getParameters().get(0).getType().isArray() && mainMethod.getParameters().get(0).getType().getComponentType().getName().equals("java.lang.String"); if (!isValidMain) { events.add(SimpleConditionEvent.violated( javaClass, javaClass.getName() + "'s only method is not a valid public static void main(String[] args)" )); } } } };
整合所有规则的完整测试方法
现在把所有规则串起来,就得到了满足你所有要求的测试:
import com.tngtech.archunit.core.domain.JavaClass; import com.tngtech.archunit.core.domain.JavaMethod; import com.tngtech.archunit.core.importer.ImportedClasses; import com.tngtech.archunit.lang.ArchCondition; import com.tngtech.archunit.lang.ConditionEvents; import com.tngtech.archunit.lang.SimpleConditionEvent; import com.tngtech.archunit.lang.syntax.ArchRuleDefinition; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.SpringBootApplication; import java.util.List; @Test void springBootApplicationClassShouldComplyWithAllSpecifications() { ArchRule springBootAppRules = ArchRuleDefinition.classes() .that().areAnnotatedWith(SpringBootApplication.class) .should() .bePublic() .andShould().haveNameMatching(".*Application") .andShould().haveSize(1) .andShould(ONLY_HAVE_VALID_MAIN_METHOD); springBootAppRules.check(importedClasses); }
补充说明
- 关于默认构造方法:Java会自动为没有显式构造的类生成无参默认构造,所以规则里没有禁止它;如果有特殊要求要严格限制(虽然普通Java类做不到完全移除),可以调整构造方法的检查逻辑。
- 测试失败时,ArchUnit会输出清晰的错误信息,告诉你具体是哪个类违反了哪条规则,方便快速定位问题。
备注:内容来源于stack exchange,提问作者PatPanda
相关产品推荐
相关产品推荐

