在ArchUnit中,可以编写以下测试用例来确保类只能访问它们实现的接口:
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.lang.syntax.ArchRuleDefinition;
import java.util.Collection;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
@AnalyzeClasses(packages = "com.example")
public class InterfaceImplementationTest {
@ArchTest
public static final ArchRule classes_should_only_access_implemented_interfaces =
noClasses().should(new ClassAccessingInterfacesOtherThanItsOwn());
private static class ClassAccessingInterfacesOtherThanItsOwn implements ArchCondition {
@Override
public void check(JavaClass javaClass, ConditionEvents events) {
Collection declaredInterfaces = javaClass.getInterfaces();
if (declaredInterfaces.isEmpty()) {
return;
}
Set implementedInterfaces = new HashSet<>(javaClass.getInterfaces());
implementedInterfaces.retainAll(JavaClass.Predicates.resideInAPackage(javaClass.getPackageName()));
Set accessedInterfaces = new HashSet<>();
for (JavaMethod javaMethod : javaClass.getMethods()) {
accessedInterfaces.addAll(javaMethod.getRawParameterTypes());
accessedInterfaces.addAll(javaMethod.getRawReturnType().resolve().getAllInterfaces());
}
for (JavaClass accessedInterface : accessedInterfaces) {
if (!implementedInterfaces.contains(accessedInterface)) {
events.add(SimpleConditionEvent.violated(javaClass,
String.format("%s accesses interface %s, which is not implemented by %s",
javaClass.getName(),
accessedInterface.getName(),
javaClass.getName())));
}
}
}
}
}
该测试用例将确保代码中没有类访问除它们实现的接口之外的其他接口。该测试用例的基本思想是:对于每个类,获取该类实现的所有接口。然后,获取该类的每个方法中使用的所有接口。如果这个方法使用了该类没有实现的接口,则引发违规事件。