TNG / ArchUnit

A Java architecture test library, to specify and assert architecture rules in plain Java
http://archunit.org
Apache License 2.0
3.18k stars 288 forks source link

Add support to analyse list of classes #1195

Open ArturoBlazquez opened 10 months ago

ArturoBlazquez commented 10 months ago

There are times when there are architecture rules that only apply to some classes, but that are not on the same package. It would be nice if we could do something similar to this

@AnalyzeClasses(classes = {First.class, Second.class})
public class MyArchitectureTest {

    @ArchTest
    public static final ArchRule myRule = ...

Something similar can be achieved using locations, but it implies either adding a lot of boilerplate code

class ListOfClassesLocations implements LocationProvider {
    @Override
    public Set<Location> get(Class<?> testClass) {
        return Stream.of(First.class, Second.class).map(clazz -> Locations.ofClass(clazz).iterator().next()).collect(Collectors.toSet());
    }
}

@AnalyzeClasses(locations = ListOfClassesLocations.class)
public class MyArchitectureTest { ...

or having to develop a custom solution like this one, that still isn't completely clean as it implies adding an extra annotation

@Target(TYPE)
@Retention(RUNTIME)
public @interface AnalyzeListOfClasses {
    Class<?>[] value();
}
public class ListOfClassesLocations implements LocationProvider {
    @Override
    public Set<Location> get(Class<?> testClass) {
        return Arrays.stream(testClass.getAnnotation(AnalyzeListOfClasses.class).value()).map(clazz -> Locations.ofClass(clazz).iterator().next()).collect(Collectors.toSet());
    }
}
@AnalyzeClasses(locations = ListOfClassesLocations.class)
@AnalyzeListOfClasses({First.class, Second.class})
public class MyArchitectureTest {

    @ArchTest
    public static final ArchRule myRule = ...
hankem commented 10 months ago

You could already use [@AnalyzeClasses's packagesOf](https://javadoc.io/doc/com.tngtech.archunit/archunit-junit5-api/latest/com/tngtech/archunit/junit/AnalyzeClasses.html#packagesOf()):

@AnalyzeClasses(packagesOf = {First.class, Second.class})
public class MyArchitectureTest {
    // ...
}

This will however not only import First and Second, but their entire packages. If your rules only apply to those classes, I'd be explicit about that in the rule definition.