Archunit cheatsheet

Archunit allows testing your “architecture” including class dependencies, cyclic dependencies, layer accesses, naming conventions, and inheritance checking.

1
2
3
4
<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit</artifactId>
</dependency>

Cyclic Dependency Test

1
2
3
4
5
6
7
@RunWith(ArchUnitRunner.class)
@AnalyzeClasses(packages = "com.test")
public class CyclicDependencyTest {
@ArchTest
public static final ArchRule rule = slices().matching("..services.(*)..")
.should().beFreeOfCycles();
}

Layer Access Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RunWith(JUnit4.class)
public class LayeredArchitectureTests {
@Test
public void layer_dependencies_are_respected() {
JavaClasses importedClasses = new ClassFileImporter().importPackages(
"..com.test..");

ArchRule myRule = layeredArchitecture()
.layer("Controllers").definedBy("..com.test.controllers..")
.layer("Services").definedBy("..com.test.services..")
.layer("Infrastructure").definedBy("..com.test.infrastructure..")
.whereLayer("Controllers").mayNotBeAccessedByAnyLayer()
.whereLayer("Services").mayOnlyBeAccessedByLayers("Controllers")
.whereLayer("Infrastructure").mayOnlyBeAccessedByLayers("Services");

myRule.check(importedClasses);
}
}

Class location tests

1
2
3
4
5
6
7
8
@RunWith(ArchUnitRunner.class)
@AnalyzeClasses(packages = "com.test")
public class RepositoryPackageTest {
@ArchTest
public ArchRule repositories_should_located_in_infrastructure = classes()
.that().areAnnotatedWith(Repository.class)
.should().resideInAPackage("..infrastructure..");
}

Method Return Type Test

1
2
3
4
5
6
7
8
9
10
@RunWith(ArchUnitRunner.class)
@AnalyzeClasses(packages = "com.test.controllers")
public class ControllerMethodReturnTypeTest {
@ArchTest
public ArchRule controller_public_methods_should_return = methods()
.that().areDeclaredInClassesThat().resideInAPackage("..controllers..")
.and().arePublic()
.should().haveRawReturnType(BaseResponse.class)
.because("here is the explanation");
}

Naming Convention Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@RunWith(ArchUnitRunner.class)
@AnalyzeClasses(packages = "com.test.controllers")
public class NamingConventionTests {
@ArchTest
ArchRule controllers_should_be_suffixed = classes()
.that().resideInAPackage("..controllers..")
.should().haveSimpleNameEndingWith("Controller");
}

@RunWith(JUnit4.class)
public class NamingConventionTests {
@Test
public void controllers_should_be_suffixed() {
JavaClasses importedClasses = new ClassFileImporter()
.importPackages("com.test.controllers");
ArchRule rule = classes()
.that().resideInAPackage("..controllers..")
.should().haveSimpleNameEndingWith("Controller");
rule.check(importedClasses);
}
}