TNG / ArchUnit

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

test if one layer does not access another #1372

Closed donalmurtagh closed 4 weeks ago

donalmurtagh commented 4 weeks ago

I'm trying to write a JUnit5 test that prevents the controller layer from accessing the repository layer. My attempt looks like this

@AnalyzeClasses(packages = "com.myapp", importOptions = ImportOption.DoNotIncludeTests.class)
public class LayeredArchitectureTests {

    @ArchTest
    static final ArchRule testLayerDependencies = layeredArchitecture().consideringAllDependencies()
        .layer("Controllers").definedBy(HasAnnotations.Predicates.annotatedWith(RestController.class))
        .layer("Services").definedBy(HasAnnotations.Predicates.annotatedWith(Service.class))
        .layer("Repositories").definedBy(JavaClass.Predicates.assignableTo(Repository.class))
        .whereLayer("Repositories").mayOnlyBeAccessedByLayers("Services", "Repositories");
}

This doesn't quite work because there are some classes outside these 3 layers that do access classes in the Repositories layer. Ideally, there should be a a way to test this directly with something like

// this mayNotBeAccessedByLayers method doesn't actually exist
.whereLayer("Repositories").mayNotBeAccessedByLayers("Controllers");

But if such a facility exists, I can't find it.

donalmurtagh commented 4 weeks ago

I figured out how to do this without using layers

    @ArchTest
    static final ArchRule noRepositoriesInControllers = noClasses()
        .that().areAnnotatedWith(RestController.class)
        .should().dependOnClassesThat().areAssignableTo(Repository.class);

Perhaps it would be helpful to add a method such as mayNotBeAccessedByLayers to the layers API, but I'll close this because I've found a resolution to the original issue I was asking about.