如何用Archunit强制要求每个类对应一个测试类?
使用Archunit强制每个类对应测试类的完整实现
你已经完成了目标类的筛选逻辑,接下来只需要在should()后添加自定义条件,验证每个筛选出的类都存在对应的测试类即可。以下是两种常见测试类命名/路径约定下的实现方案:
方案1:测试类以Test为后缀(如UserService → UserServiceTest)
直接通过类名拼接+包内查找的方式验证:
classes().that() .areNotInterfaces() .and() .areNotAnonymousClasses() .and() .areNotRecords() .and() .areNotEnums() .should(new ArchCondition<JavaClass>("have a matching test class with 'Test' suffix") { @Override public void check(JavaClass javaClass, ConditionEvents events) { // 拼接测试类名 String testClassName = javaClass.getSimpleName() + "Test"; // 在同一个包下查找测试类(也可指定固定测试包前缀,比如javaClass.getPackageName().replace("main", "test")) Optional<JavaClass> testClass = javaClass.getPackage().getClassByName(testClassName); if (testClass.isEmpty()) { events.add(SimpleConditionEvent.violated(javaClass, "Missing test class: " + testClassName)); } } });
方案2:测试类与主类包结构完全对应(Maven/Gradle标准结构)
如果你的项目遵循src/main/java和src/test/java的包结构一致约定,可以先分别导入主类和测试类集合,再做匹配检查:
// 导入主代码包下的所有类 JavaClasses mainClasses = new ClassFileImporter() .importPackages("com.yourproject"); // 导入测试代码包下的所有类 JavaClasses testClasses = new ClassFileImporter() .importPackages("com.yourproject"); // 定义规则 ArchRule testClassRequiredRule = classes().that() .areNotInterfaces() .and() .areNotAnonymousClasses() .and() .areNotRecords() .and() .areNotEnums() .and() .areIn(mainClasses) .should(haveCorrespondingTestClass(testClasses)); // 自定义匹配逻辑 private static ArchCondition<JavaClass> haveCorrespondingTestClass(JavaClasses testClasses) { return new ArchCondition<>("have a matching test class in the corresponding package") { @Override public void check(JavaClass javaClass, ConditionEvents events) { boolean testClassExists = testClasses.stream() .anyMatch(testClazz -> // 匹配类名(后缀Test)+ 相同包路径 testClazz.getSimpleName().equals(javaClass.getSimpleName() + "Test") && testClazz.getPackageName().equals(javaClass.getPackageName()) ); if (!testClassExists) { events.add(SimpleConditionEvent.violated(javaClass, String.format("No test class found for %s in package %s", javaClass.getSimpleName(), javaClass.getPackageName()))); } } }; }
可选优化
- 排除无需测试的类:比如启动类、配置类,只需在筛选条件中添加
.and().areNotAssignableTo(Application.class)或.and().haveSimpleNameNotMatching(".*Config") - 适配其他测试类命名:如果测试类是
TestXxx前缀,只需修改类名拼接逻辑为"Test" + javaClass.getSimpleName()
内容的提问来源于stack exchange,提问作者kylie.zoltan
相关产品推荐
相关产品推荐

